source: rtems/c/src/lib/libbsp/arm/altera-cyclone-v/hwlib/src/hwmgr/alt_qspi.c @ 76386c1

4.115
Last change on this file since 76386c1 was 76386c1, checked in by Sebastian Huber <sebastian.huber@…>, on Aug 26, 2014 at 2:00:44 PM

bsp/altera-cyclone-v: Add DMA support hwlib files

  • Property mode set to 100644
File size: 74.7 KB
Line 
1/******************************************************************************
2*
3* alt_qspi.c - API for the Altera SoC FPGA QSPI device.
4*
5******************************************************************************/
6
7/******************************************************************************
8 *
9 * Copyright 2013 Altera Corporation. All Rights Reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 *
21 * 3. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO
27 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 * OF SUCH DAMAGE.
34 *
35 ******************************************************************************/
36
37#include <string.h>
38#include <stdio.h>
39#include <inttypes.h>
40#include "hwlib.h"
41#include "alt_clock_manager.h"
42#include "alt_qspi.h"
43#include "alt_qspi_private.h"
44#include "socal/alt_qspi.h"
45#include "socal/alt_rstmgr.h"
46#include "socal/alt_sysmgr.h"
47#include "socal/hps.h"
48#include "socal/socal.h"
49
50/////
51
52// NOTE: To enable debugging output, delete the next line and uncomment the
53//   line after.
54#define dprintf(...)
55// #define dprintf printf
56
57/////
58
59#define MIN(a, b) ((a) > (b) ? (b) : (a))
60
61// qspi_clk operating frequency range.
62#define ALT_QSPI_CLK_FREQ_MIN ((alt_freq_t)0)
63#define ALT_QSPI_CLK_FREQ_MAX ((alt_freq_t)432000000)
64
65// The set of all valid QSPI controller interrupt status mask values.
66#define ALT_QSPI_INT_STATUS_ALL ( \
67        ALT_QSPI_INT_STATUS_MODE_FAIL         | \
68        ALT_QSPI_INT_STATUS_UFL               | \
69        ALT_QSPI_INT_STATUS_IDAC_OP_COMPLETE  | \
70        ALT_QSPI_INT_STATUS_IDAC_OP_REJECT    | \
71        ALT_QSPI_INT_STATUS_WR_PROT_VIOL      | \
72        ALT_QSPI_INT_STATUS_ILL_AHB_ACCESS    | \
73        ALT_QSPI_INT_STATUS_IDAC_WTRMK_TRIG   | \
74        ALT_QSPI_INT_STATUS_RX_OVF            | \
75        ALT_QSPI_INT_STATUS_TX_FIFO_NOT_FULL  | \
76        ALT_QSPI_INT_STATUS_TX_FIFO_FULL      | \
77        ALT_QSPI_INT_STATUS_RX_FIFO_NOT_EMPTY | \
78        ALT_QSPI_INT_STATUS_RX_FIFO_FULL      | \
79        ALT_QSPI_INT_STATUS_IDAC_RD_FULL        \
80        )
81
82static uint32_t qspi_device_size = 0;
83
84/////
85
86static ALT_STATUS_CODE alt_qspi_device_status(uint32_t * status)
87{
88    // Read flag status register through STIG
89    return alt_qspi_stig_rd_cmd(ALT_QSPI_STIG_OPCODE_RDSR, 0, 1, status, 10000);
90}
91
92#if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
93static ALT_STATUS_CODE alt_qspi_N25Q_device_flag(uint32_t * flagsr)
94{
95    if (qspi_device_size < 0x4000000)
96    {
97        return ALT_E_SUCCESS;
98    }
99
100    // Read flag status register through STIG
101    return alt_qspi_stig_rd_cmd(ALT_QSPI_STIG_OPCODE_RDFLGSR, 0, 1, flagsr, 10000);
102}
103
104// NOTE: This must be called after QSPI has been enabled. Communications with
105//   the device will not happen until QSPI is enabled.
106static inline ALT_STATUS_CODE alt_qspi_N25Q_enable(void)
107{
108    ALT_STATUS_CODE status = ALT_E_SUCCESS;
109
110    // Reset the volatile memory on the N25Q
111
112    if (status == ALT_E_SUCCESS)
113    {
114        status = alt_qspi_stig_cmd(ALT_QSPI_STIG_OPCODE_RESET_EN, 0, 10000);
115    }
116
117    if (status == ALT_E_SUCCESS)
118    {
119        status = alt_qspi_stig_cmd(ALT_QSPI_STIG_OPCODE_RESET_MEM, 0, 10000);
120    }
121
122    /////
123
124    if (status == ALT_E_SUCCESS)
125    {
126        ALT_QSPI_DEV_INST_CONFIG_t cfg =
127        {
128            .op_code        = ALT_QSPI_STIG_OPCODE_FASTREAD_QUAD_IO,
129            .inst_type      = ALT_QSPI_MODE_SINGLE, // RDID does not support QUAD.
130            .addr_xfer_type = ALT_QSPI_MODE_QUAD,
131            .data_xfer_type = ALT_QSPI_MODE_QUAD,
132            .dummy_cycles   = 10
133        };
134
135        status = alt_qspi_device_read_config_set(&cfg);
136    }
137
138/*
139    // CASE 157096: Investigate using QUAD for writes.
140    if (status == ALT_E_SUCCESS)
141    {
142        ALT_QSPI_DEV_INST_CONFIG_t cfg =
143        {
144            .op_code        = ALT_QSPI_STIG_OPCODE_PP,
145            .inst_type      = ALT_QSPI_MODE_SINGLE,
146            .addr_xfer_type = ALT_QSPI_MODE_QUAD,
147            .data_xfer_type = ALT_QSPI_MODE_QUAD,
148            .dummy_cycles   = 0
149        };
150
151        status = alt_qspi_device_write_config_set(&cfg);
152    }
153*/
154
155    return status;
156}
157
158static ALT_STATUS_CODE alt_qspi_N25Q_flag_wait_for_program(uint32_t timeout)
159{
160    // The flag status register is only available on the 512 Mib and 1 Gib
161    // (64 MiB and 128 MiB) Micron parts.
162    if (qspi_device_size < 0x4000000)
163    {
164        return ALT_E_SUCCESS;
165    }
166
167    ALT_STATUS_CODE status = ALT_E_SUCCESS;
168
169    uint32_t time_out = timeout;
170    uint32_t stat = 0;
171    bool infinite = (timeout == ALT_QSPI_TIMEOUT_INFINITE);
172
173    do
174    {
175        status = alt_qspi_device_status(&stat);
176        if (status != ALT_E_SUCCESS)
177        {
178            break;
179        }
180        if (!ALT_QSPI_STIG_SR_BUSY_GET(stat))
181        {
182            break;
183        }
184    }
185    while (time_out-- || infinite);
186
187    if (time_out == (uint32_t)-1 && !infinite)
188    {
189        status = ALT_E_TMO;
190    }
191
192    if (status == ALT_E_SUCCESS)
193    {
194        uint32_t flagsr = 0;
195
196        do
197        {
198            status = alt_qspi_N25Q_device_flag(&flagsr);
199            if (status != ALT_E_SUCCESS)
200            {
201                break;
202            }
203            if (ALT_QSPI_STIG_FLAGSR_PROGRAMREADY_GET(flagsr))
204            {
205                break;
206            }
207        }
208        while (timeout-- || infinite);
209
210        if (timeout == (uint32_t)-1 && !infinite)
211        {
212            status = ALT_E_TMO;
213        }
214
215        if (status == ALT_E_SUCCESS)
216        {
217            if (ALT_QSPI_STIG_FLAGSR_PROGRAMERROR_GET(flagsr))
218            {
219                status = ALT_E_ERROR;
220            }
221        }
222    }
223    return status;
224}
225
226static ALT_STATUS_CODE alt_qspi_N25Q_flag_wait_for_erase(uint32_t timeout)
227{
228    // The flag status register is only available on the 512 Mib and 1 Gib
229    // (64 MiB and 128 MiB) Micron parts.
230    if (qspi_device_size < 0x4000000)
231    {
232        return ALT_E_SUCCESS;
233    }
234
235    ALT_STATUS_CODE status = ALT_E_SUCCESS;
236
237    uint32_t time_out = timeout;
238    uint32_t stat = 0;
239    bool infinite = (timeout == ALT_QSPI_TIMEOUT_INFINITE);
240
241    do
242    {
243        status = alt_qspi_device_status(&stat);
244        if (status != ALT_E_SUCCESS)
245        {
246            break;
247        }
248        if (!ALT_QSPI_STIG_SR_BUSY_GET(stat))
249        {
250            break;
251        }
252    }
253    while (time_out-- || infinite);
254
255    if (time_out == (uint32_t)-1 && !infinite)
256    {
257        status = ALT_E_TMO;
258    }
259
260    if (status == ALT_E_SUCCESS)
261    {
262
263        uint32_t flagsr = 0;
264
265        do
266        {
267            status = alt_qspi_N25Q_device_flag(&flagsr);
268            if (status != ALT_E_SUCCESS)
269            {
270                break;
271            }
272            if (ALT_QSPI_STIG_FLAGSR_ERASEREADY_GET(flagsr))
273            {
274                break;
275            }
276        }
277        while (timeout-- || infinite);
278
279        if (timeout == (uint32_t)-1 && !infinite)
280        {
281            status = ALT_E_TMO;
282        }
283
284        if (status == ALT_E_SUCCESS)
285        {
286            if (ALT_QSPI_STIG_FLAGSR_ERASEERROR_GET(flagsr))
287            {
288                status = ALT_E_ERROR;
289            }
290        }
291    }
292 
293    return status;
294}
295#endif
296
297//
298// A helper function which converts a ns interval into a delay interval for a given MHz.
299// The +999 is there to round up the result.
300//
301static inline int alt_qspi_ns_to_multiplier(int ns, int mhz)
302{
303    return ((ns * mhz) + 999) / 1000;
304}
305
306ALT_STATUS_CODE alt_qspi_init(void)
307{
308    ALT_STATUS_CODE status = ALT_E_SUCCESS;
309    alt_freq_t qspi_clk_freq = 0;
310
311    // Validate QSPI module input clocks.
312    //  - pclk    - l4_mp_clk
313    //  - hclk    - l4_mp_clk
314    //  - ref_clk - qspi_clk
315
316    // Check and validate the QSPI ref_clk which is connected to the HPS qspi_clk.
317    if (status == ALT_E_SUCCESS)
318    {
319        if (alt_clk_is_enabled(ALT_CLK_QSPI) != ALT_E_TRUE)
320        {
321            status = ALT_E_BAD_CLK;
322        }
323    }
324
325    if (status == ALT_E_SUCCESS)
326    {
327        status = alt_clk_freq_get(ALT_CLK_QSPI, &qspi_clk_freq);
328        if (status == ALT_E_SUCCESS)
329        {
330            if (qspi_clk_freq > ALT_QSPI_CLK_FREQ_MAX)
331            {
332                return ALT_E_BAD_CLK;
333            }
334        }
335    }
336
337    int qspi_clk_mhz = qspi_clk_freq / 1000000;
338
339    /////
340
341    // Take QSPI controller out of reset.
342    alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_QSPI_SET_MSK);
343
344    /////
345
346    // Configure the device timing
347
348    if (status == ALT_E_SUCCESS)
349    {
350        ALT_QSPI_TIMING_CONFIG_t timing_cfg =
351        {
352            .clk_phase  = (ALT_QSPI_CLK_PHASE_t)ALT_QSPI_CFG_SELCLKPHASE_RESET,
353            .clk_pol    = (ALT_QSPI_CLK_POLARITY_t)ALT_QSPI_CFG_SELCLKPOL_RESET,
354            .cs_da      = alt_qspi_ns_to_multiplier(ALT_QSPI_TSHSL_NS_DEF, qspi_clk_mhz),
355            .cs_dads    = alt_qspi_ns_to_multiplier(ALT_QSPI_TSD2D_NS_DEF, qspi_clk_mhz),
356            .cs_eot     = alt_qspi_ns_to_multiplier(ALT_QSPI_TCHSH_NS_DEF, qspi_clk_mhz),
357            .cs_sot     = alt_qspi_ns_to_multiplier(ALT_QSPI_TSLCH_NS_DEF, qspi_clk_mhz),
358            .rd_datacap = 1
359        };
360
361        dprintf("DEBUG[QSPI]: cs_da   = %" PRIu32 ".\n", timing_cfg.cs_da);
362        dprintf("DEBUG[QSPI]: cs_dads = %" PRIu32 ".\n", timing_cfg.cs_dads);
363        dprintf("DEBUG[QSPI]: cs_eot  = %" PRIu32 ".\n", timing_cfg.cs_eot);
364        dprintf("DEBUG[QSPI]: cs_sot  = %" PRIu32 ".\n", timing_cfg.cs_sot);
365
366        status = alt_qspi_timing_config_set(&timing_cfg);
367    }
368
369    /////
370
371    // Configure the remap address register, no remap
372
373    if (status == ALT_E_SUCCESS)
374    {
375        status = alt_qspi_ahb_remap_address_set(0);
376    }
377
378    // Configure the interrupt mask register, disabled all first
379
380    if (status == ALT_E_SUCCESS)
381    {
382        status = alt_qspi_int_disable(ALT_QSPI_INT_STATUS_ALL);
383    }
384
385    // Configure the baud rate divisor
386    // CASE 157095: Investigate using 108 MHz, and tweaking the rd_datacap param.
387
388    if (status == ALT_E_SUCCESS)
389    {
390        uint32_t device_sclk_mhz = 54;
391        uint32_t div_actual = (qspi_clk_mhz + (device_sclk_mhz - 1)) / device_sclk_mhz;
392        dprintf("DEBUG[QSPI]: div_actual = %" PRIu32 ".\n", div_actual);
393
394        ALT_QSPI_BAUD_DIV_t div_bits = (ALT_QSPI_BAUD_DIV_t)(((div_actual + 1) / 2) - 1);
395        status = alt_qspi_baud_rate_div_set(div_bits);
396    }
397
398    return status;
399}
400
401ALT_STATUS_CODE alt_qspi_uninit(void)
402{
403    // Put QSPI controller into reset.
404    alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_QSPI_SET_MSK);
405
406    return ALT_E_SUCCESS;
407}
408
409ALT_STATUS_CODE alt_qspi_disable(void)
410{
411    alt_clrbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_EN_SET_MSK);
412
413    return ALT_E_SUCCESS;
414}
415
416ALT_STATUS_CODE alt_qspi_enable(void)
417{
418    alt_setbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_EN_SET_MSK);
419
420    ALT_STATUS_CODE status = ALT_E_SUCCESS;
421
422    /////
423
424    // Device specific configuration
425
426#if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
427    if (status == ALT_E_SUCCESS)
428    {
429        status = alt_qspi_N25Q_enable();
430    }
431#endif
432
433    uint32_t rdid = 0;
434
435    // Query device capabilities
436    // This requires QSPI to be enabled.
437
438    if (status == ALT_E_SUCCESS)
439    {
440        status = alt_qspi_device_rdid(&rdid);
441    }
442
443    if (status == ALT_E_SUCCESS)
444    {
445        // NOTE: The size code seems to be a form of BCD (binary coded decimal).
446        //   The first nibble is the 10's digit and the second nibble is the 1's
447        //   digit in the number of bytes.
448
449        // Capacity ID samples:
450        //  0x15 :   16 Mb =>   2 MiB => 1 << 21 ; BCD=15
451        //  0x16 :   32 Mb =>   4 MiB => 1 << 22 ; BCD=16
452        //  0x17 :   64 Mb =>   8 MiB => 1 << 23 ; BCD=17
453        //  0x18 :  128 Mb =>  16 MiB => 1 << 24 ; BCD=18
454        //  0x19 :  256 Mb =>  32 MiB => 1 << 25 ; BCD=19
455        //  0x1a
456        //  0x1b
457        //  0x1c
458        //  0x1d
459        //  0x1e
460        //  0x1f
461        //  0x20 :  512 Mb =>  64 MiB => 1 << 26 ; BCD=20
462        //  0x21 : 1024 Mb => 128 MiB => 1 << 27 ; BCD=21
463
464        int cap_code = ALT_QSPI_STIG_RDID_CAPACITYID_GET(rdid);
465
466        if ( ((cap_code >> 4) > 0x9) || ((cap_code & 0xf) > 0x9))
467        {
468            // If a non-valid BCD value is detected at the top or bottom nibble, chances
469            // are that the chip has a problem.
470
471            dprintf("DEBUG[QSPI]: Invalid CapacityID encountered: 0x%02x.\n", cap_code);
472            status = ALT_E_ERROR;
473        }
474        else
475        {
476            int cap_decoded = ((cap_code >> 4) * 10) + (cap_code & 0xf);
477
478            qspi_device_size = 1 << (cap_decoded + 6);
479
480            dprintf("DEBUG[QSPI]: Device size = 0x%" PRIx32 ".\n", qspi_device_size);
481        }
482    }
483
484    // Configure the device size and address bytes
485
486    if (status == ALT_E_SUCCESS)
487    {
488        ALT_QSPI_DEV_SIZE_CONFIG_t size_cfg =
489        {
490            .block_size         = ALT_QSPI_DEVSZ_BYTESPERSUBSECTOR_RESET,  // 0x10  => 2^16 = 64 KiB
491            .page_size          = ALT_QSPI_DEVSZ_BYTESPERDEVICEPAGE_RESET, // 0x100 => 256 B
492            .addr_size          = ALT_QSPI_DEVSZ_NUMADDRBYTES_RESET,       // 0x2   => 3 bytes or 0x00ffffff mask.
493            .lower_wrprot_block = 0,
494            .upper_wrprot_block = (qspi_device_size - 1) >> 16,
495            .wrprot_enable      = ALT_QSPI_WRPROT_EN_RESET
496        };
497
498        status = alt_qspi_device_size_config_set(&size_cfg);
499    }
500
501    /////
502
503    // Configure the DMA parameters
504
505    // This will allow DMA to work well without much intervention by users.
506
507    if (status == ALT_E_SUCCESS)
508    {
509        status = alt_qspi_dma_config_set(4, 32);
510    }
511
512    /////
513
514    return status;
515}
516
517/////
518
519uint32_t alt_qspi_int_status_get(void)
520{
521    // Read and return the value of the QSPI controller Interrupt Status
522    // Register (irqstat).
523    return alt_read_word(ALT_QSPI_IRQSTAT_ADDR);
524}
525
526ALT_STATUS_CODE alt_qspi_int_clear(const uint32_t mask)
527{
528    // Check that the [mask] contains valid interrupt status conditions values.
529    if ((ALT_QSPI_INT_STATUS_ALL & mask) == 0)
530    {
531        return ALT_E_BAD_ARG;
532    }
533
534    // Write 1's to clear the desired interrupt status condition(s).
535    alt_write_word(ALT_QSPI_IRQSTAT_ADDR, mask);
536
537    return ALT_E_SUCCESS;
538}
539
540ALT_STATUS_CODE alt_qspi_int_disable(const uint32_t mask)
541{
542    if (alt_qspi_is_idle() == false)
543    {
544        return ALT_E_ERROR;
545    }
546
547    // Check that the [mask] contains valid interrupt status conditions values.
548    if ((ALT_QSPI_INT_STATUS_ALL & mask) == 0)
549    {
550        return ALT_E_BAD_ARG;
551    }
552
553    // Write 0's to disable the desired interrupt status condition(s).
554    alt_clrbits_word(ALT_QSPI_IRQMSK_ADDR, mask);
555
556    return ALT_E_SUCCESS;
557}
558
559ALT_STATUS_CODE alt_qspi_int_enable(const uint32_t mask)
560{
561    if (alt_qspi_is_idle() == false)
562    {
563        return ALT_E_ERROR;
564    }
565
566    // Check that the [mask] contains valid interrupt status conditions values.
567    if ((ALT_QSPI_INT_STATUS_ALL & mask) == 0)
568    {
569        return ALT_E_BAD_ARG;
570    }
571
572    // Write 1's to enable the desired interrupt status condition(s).
573    alt_setbits_word(ALT_QSPI_IRQMSK_ADDR, mask);
574
575    return ALT_E_SUCCESS;
576}
577
578/////
579
580bool alt_qspi_is_idle(void)
581{
582    // If the idle field of the QSPI configuration register is 1 then the serial
583    // interface and QSPI pipeline is idle.
584    return ALT_QSPI_CFG_IDLE_GET(alt_read_word(ALT_QSPI_CFG_ADDR)) == 1;
585}
586
587/////
588
589static ALT_STATUS_CODE alt_qspi_indirect_write_start_bank(uint32_t dst, size_t length);
590
591static ALT_STATUS_CODE alt_qspi_indirect_page_bound_write_helper(uint32_t dst, const char * src, size_t length)
592{
593    ALT_STATUS_CODE status = ALT_E_SUCCESS;
594
595    if (status == ALT_E_SUCCESS)
596    {
597        status = alt_qspi_indirect_write_start_bank(dst, length);
598    }
599
600    if (status == ALT_E_SUCCESS)
601    {
602        uint32_t write_count = 0;
603        uint32_t write_capacity = ALT_QSPI_SRAM_FIFO_ENTRY_COUNT - alt_qspi_sram_partition_get();
604
605        while (write_count < length)
606        {
607            uint32_t space = write_capacity - alt_qspi_indirect_write_fill_level();
608            space = MIN(space, (length - write_count)/ sizeof(uint32_t));
609
610            const uint32_t * data = (const uint32_t *)(src + write_count);
611            for (uint32_t i = 0; i < space; ++i)
612            {
613                alt_write_word(ALT_QSPIDATA_ADDR, *data++);
614            }
615
616            write_count += space * sizeof(uint32_t);
617        }
618    }
619
620    if (status == ALT_E_SUCCESS)
621    {
622        status = alt_qspi_indirect_write_finish();
623    }
624
625    return status;
626}
627
628static ALT_STATUS_CODE alt_qspi_indirect_subsector_aligned_write_helper(const char * data, uint32_t subsec_addr)
629{
630    ALT_STATUS_CODE status = ALT_E_SUCCESS;
631
632    for (int i = 0; i < ALT_QSPI_SUBSECTOR_SIZE / ALT_QSPI_PAGE_SIZE; i++)
633    {
634        int offset = i * ALT_QSPI_PAGE_SIZE;
635
636        status = alt_qspi_indirect_page_bound_write_helper(subsec_addr + offset, data + offset, ALT_QSPI_PAGE_SIZE);
637        if (status != ALT_E_SUCCESS)
638        {
639            break;
640        }
641    }
642
643    return status;
644}
645
646static ALT_STATUS_CODE alt_qspi_indirect_read_start_bank(uint32_t src, size_t size);
647
648//
649// This helper function reads a segment of data, which is limited to 1 bank
650// (24 bits of addressing).
651//
652static ALT_STATUS_CODE alt_qspi_read_bank(char * dst, uint32_t src, size_t size)
653{
654    ALT_STATUS_CODE status = ALT_E_SUCCESS;
655
656    if (status == ALT_E_SUCCESS)
657    {
658        status = alt_qspi_indirect_read_start_bank(src, size);
659    }
660
661    if (status == ALT_E_SUCCESS)
662    {
663        uint32_t read_count = 0;
664
665        while (!alt_qspi_indirect_read_is_complete())
666        {
667            uint32_t level = alt_qspi_indirect_read_fill_level();
668//            level = MIN(level, (size - read_count) / sizeof(uint32_t));
669
670            uint32_t * data = (uint32_t *)(dst + read_count);
671            for (uint32_t i = 0; i < level; ++i)
672            {
673                *data++ = alt_read_word(ALT_QSPIDATA_ADDR);
674            }
675
676            read_count += level * sizeof(uint32_t);
677        }
678    }
679
680    if (status == ALT_E_SUCCESS)
681    {
682        status = alt_qspi_indirect_read_finish();
683    }
684
685    return status;
686}
687
688ALT_STATUS_CODE alt_qspi_read(void * dst, uint32_t src, size_t size)
689{
690    if (src >= qspi_device_size)
691    {
692        return ALT_E_ERROR;
693    }
694
695    if (src + size - 1 >= qspi_device_size)
696    {
697        return ALT_E_ERROR;
698    }
699
700    if (size == 0)
701    {
702        return ALT_E_SUCCESS;
703    }
704
705    if ((uintptr_t)dst & 0x3)
706    {
707        return ALT_E_ERROR;
708    }
709
710    if (src & 0x3)
711    {
712        return ALT_E_ERROR;
713    }
714
715    if (size & 0x3)
716    {
717        return ALT_E_ERROR;
718    }
719
720    /////
721
722    // Verify that there is not already a read in progress.
723    if (ALT_QSPI_INDRD_RD_STAT_GET(alt_read_word(ALT_QSPI_INDRD_ADDR)))
724    {
725        return ALT_E_ERROR;
726    }
727
728    /////
729
730    ALT_STATUS_CODE status = ALT_E_SUCCESS;
731
732    //
733    // bank_count : The number of bank(s) affected, including partial banks.
734    // bank_addr  : The aligned address of the first affected bank, including partial bank(s).
735    // bank_ofst  : The offset of the bank to read. Only used when reading the first bank.
736    //
737    uint32_t bank_count = ((src + size - 1) >> 24) - (src >> 24) + 1;
738    uint32_t bank_addr  = src & ALT_QSPI_BANK_ADDR_MSK;
739    uint32_t bank_ofst  = src & (ALT_QSPI_BANK_SIZE - 1);
740
741    char * data = (char *)dst;
742
743    uint32_t copy_length = MIN(size, ALT_QSPI_BANK_SIZE - bank_ofst);
744
745    dprintf("DEBUG[QSPI]: read(): bulk: mem_addr = %p; flash_addr = 0x%" PRIx32 ".\n", data, src);
746    dprintf("DEBUG[QSPI]: read(): bulk: bank_count = 0x%" PRIx32 ", bank_ofst = 0x%" PRIx32 ".\n", bank_count, bank_ofst);
747
748    for (uint32_t i = 0; i < bank_count; ++i)
749    {
750        dprintf("DEBUG[QSPI]: read(): bank 0x%" PRIx32 "; copy_length = 0x%" PRIx32 ".\n", bank_addr >> 24, copy_length);
751
752        status = alt_qspi_device_bank_select(bank_addr >> 24);
753        if (status != ALT_E_SUCCESS)
754        {
755            break;
756        }
757
758        status = alt_qspi_read_bank(dst, bank_ofst, copy_length);
759        if (status != ALT_E_SUCCESS)
760        {
761            break;
762        }
763
764        bank_addr += ALT_QSPI_BANK_SIZE;
765        data += copy_length;
766        size -= copy_length;
767
768        copy_length = MIN(size, ALT_QSPI_BANK_SIZE);
769    }
770
771    return status;
772}
773
774static ALT_STATUS_CODE alt_qspi_write_bank(uint32_t dst, const char * src, size_t size)
775{
776    ALT_STATUS_CODE status = ALT_E_SUCCESS;
777
778    /////
779
780    uint32_t page_ofst  = dst & (ALT_QSPI_PAGE_SIZE - 1);
781    uint32_t write_size = MIN(size, ALT_QSPI_PAGE_SIZE - page_ofst);
782
783    while (size)
784    {
785        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);
786
787        status = alt_qspi_indirect_page_bound_write_helper(dst, src, write_size);
788        if (status != ALT_E_SUCCESS)
789        {
790            break;
791        }
792
793        dst  += write_size;
794        src  += write_size;
795        size -= write_size;
796
797        write_size = MIN(size, ALT_QSPI_PAGE_SIZE);
798    }
799
800    return status;
801}
802
803ALT_STATUS_CODE alt_qspi_write(uint32_t dst, const void * src, size_t size)
804{
805    if (dst >= qspi_device_size)
806    {
807        return ALT_E_ERROR;
808    }
809
810    if (dst + size - 1 >= qspi_device_size)
811    {
812        return ALT_E_ERROR;
813    }
814
815    if (size == 0)
816    {
817        return ALT_E_SUCCESS;
818    }
819
820    if ((uintptr_t)src & 0x3)
821    {
822        return ALT_E_ERROR;
823    }
824
825    if (dst & 0x3)
826    {
827        return ALT_E_ERROR;
828    }
829
830    if (size & 0x3)
831    {
832        return ALT_E_ERROR;
833    }
834
835    /////
836
837    // Verify that there is not already a write in progress.
838    if (ALT_QSPI_INDWR_RDSTAT_GET(alt_read_word(ALT_QSPI_INDWR_ADDR)))
839    {
840        return ALT_E_ERROR;
841    }
842
843    /////
844
845    ALT_STATUS_CODE status = ALT_E_SUCCESS;
846
847    uint32_t bank_count = ((dst + size - 1) >> 24) - (dst >> 24) + 1;
848    uint32_t bank_addr  = dst & ALT_QSPI_BANK_ADDR_MSK;
849    uint32_t bank_ofst  = dst & (ALT_QSPI_BANK_SIZE - 1);
850
851    const char * data  = src;
852
853    uint32_t copy_length = MIN(size, ALT_QSPI_BANK_SIZE - bank_ofst);
854
855    dprintf("DEBUG[QSPI]: write(): bulk: flash_addr = 0x%" PRIx32 "; mem_addr = %p.\n", dst, data);
856    dprintf("DEBUG[QSPI]: write(): bulk: bank_count = 0x%" PRIx32 ", bank_ofst = 0x%" PRIx32 ".\n", bank_count, bank_ofst);
857
858    for (uint32_t i = 0; i < bank_count; ++i)
859    {
860        dprintf("DEBUG[QSPI]: write(): bank 0x%" PRIx32 "; copy_length = 0x%" PRIx32 ".\n", bank_addr >> 24, copy_length);
861
862        status = alt_qspi_device_bank_select(bank_addr >> 24);
863        if (status != ALT_E_SUCCESS)
864        {
865            break;
866        }
867
868        status = alt_qspi_write_bank(bank_ofst, data, copy_length);
869        if (status != ALT_E_SUCCESS)
870        {
871            break;
872        }
873
874        bank_addr += ALT_QSPI_BANK_SIZE;
875        data += copy_length;
876        size -= copy_length;
877
878        copy_length = MIN(size, ALT_QSPI_BANK_SIZE);
879    }
880
881    return status;
882}
883
884static ALT_STATUS_CODE alt_qspi_erase_subsector_bank(uint32_t addr);
885
886static ALT_STATUS_CODE alt_qspi_replace_bank(uint32_t dst, const char * src, size_t size)
887{
888    ALT_STATUS_CODE status = ALT_E_SUCCESS;
889
890    //
891    // subsec_count        : The total number of affected subsector(s),
892    //                       including partial subsector(s).
893    // subsec_addr         : The aligned address of the next affected subsector,
894    //                       including partial subsector(s).
895    // subsec_partial_head : The number of subsector unaligned data to be
896    //                       written out at the start of the flash write
897    //                       request. This data ends at the end of the subsector
898    //                       or earlier depending on the number of data to be
899    //                       written.
900    // subsec_partial_tail : The number of subsector unaligned data to be
901    //                       written out at the end of the flash write request.
902    //                       This data starts at the start of the subsector. If
903    //                       only a single subsector is written (partial or
904    //                       full), this value will be zero.
905    //
906
907    uint32_t subsec_count = ((dst + size - 1) >> 12) - (dst >> 12) + 1;
908    uint32_t subsec_addr  = dst & ALT_QSPI_SUBSECTOR_ADDR_MSK;
909
910    uint32_t subsec_partial_head = MIN(ALT_QSPI_SUBSECTOR_SIZE - (dst & (ALT_QSPI_SUBSECTOR_SIZE - 1)), size) & (ALT_QSPI_SUBSECTOR_SIZE - 1);
911    uint32_t subsec_partial_tail = (size - subsec_partial_head) & (ALT_QSPI_SUBSECTOR_SIZE - 1);
912
913    dprintf("DEBUG[QSPI]: replace(): report: dst = 0x%" PRIx32 "; size = 0x%x.\n",
914            dst, size);
915    dprintf("DEBUG[QSPI]: replace(): report: subsec_count = 0x%" PRIx32 "; subsec_addr = 0x%" PRIx32 ".\n",
916            subsec_count, subsec_addr);
917    dprintf("DEBUG[QSPI]: replace(): report: partial_head = 0x%" PRIx32 "; partial_tail = 0x%" PRIx32 ".\n",
918            subsec_partial_head, subsec_partial_tail);
919
920    // Write the first subsector, partial case.
921
922    if (subsec_partial_head)
923    {
924        // The write request is not aligned to a subsector so we must do the
925        // Read-Modify-Write cycle to preserve the existing data at the head of
926        // the subsector not affected by the write.
927
928        char subsec_buf[ALT_QSPI_SUBSECTOR_SIZE];
929
930        uint32_t subsec_ofst = dst & ~ALT_QSPI_SUBSECTOR_ADDR_MSK;
931
932        // - Read the subsector into buffer
933        // - Erase that subsector
934        // - Copy in the user data into buffer
935        // - Write out buffer to subsector
936
937        if (status == ALT_E_SUCCESS)
938        {
939            status = alt_qspi_read_bank(subsec_buf, subsec_addr, subsec_ofst);
940        }
941        if (status == ALT_E_SUCCESS)
942        {
943            status = alt_qspi_erase_subsector_bank(subsec_addr);
944        }
945        if (status == ALT_E_SUCCESS)
946        {
947            memcpy(subsec_buf + subsec_ofst, src, subsec_partial_head);
948            status = alt_qspi_indirect_subsector_aligned_write_helper(subsec_buf, subsec_addr);
949        }
950
951        // Do some bookkeeping on the user buffer information
952        src  += subsec_partial_head;
953        size -= subsec_partial_head;
954
955        // Do some bookkeeping on the subsector tracking
956        subsec_count--;
957        subsec_addr += ALT_QSPI_SUBSECTOR_SIZE;
958
959        dprintf("DEBUG[QSPI]: replace(): partial head: subsec_ofst = 0x%" PRIx32 "; size left = 0x%x; status = %" PRIi32 ".\n",
960                subsec_ofst, size, status);
961    }
962
963    // If there is a partial tail, then take 1 off the subsec_count. This way
964    // the following loop will write out all the complete subsectors. The tail
965    // will be written out afterwards.
966   
967    if (subsec_partial_tail)
968    {
969        subsec_count--;
970    }
971
972    // Write the aligned subsectors following any partial subsectors.
973
974    for (uint32_t i = 0; i < subsec_count; ++i)
975    {
976        // - Erase subsector
977        // - Write out buffer to subsector
978
979        if (status == ALT_E_SUCCESS)
980        {
981            status = alt_qspi_erase_subsector_bank(subsec_addr);
982        }
983        if (status == ALT_E_SUCCESS)
984        {
985            status = alt_qspi_indirect_subsector_aligned_write_helper(src, subsec_addr);
986        }
987
988        src  += ALT_QSPI_SUBSECTOR_SIZE;
989        size -= ALT_QSPI_SUBSECTOR_SIZE;
990
991        // Don't modify subsec_count as it's being used by the loop.
992        subsec_addr += ALT_QSPI_SUBSECTOR_SIZE;
993
994        dprintf("DEBUG[QSPI]: replace(): subsec aligned: size left = 0x%x, status = %" PRIi32 ".\n",
995                size, status);
996    }
997
998    // Write the last subsector, partial case.
999
1000    if (subsec_partial_tail)
1001    {
1002        // The write request is not aligned to a subsector so we must do the
1003        // Read-Modify-Write cycle to preserve the existing data at the end of
1004        // the subsector not affected by the write.
1005
1006        char subsec_buf[ALT_QSPI_SUBSECTOR_SIZE];
1007
1008        // - Read the subsector into buffer
1009        // - Erase that subsector
1010        // - Copy in the user data into buffer
1011        // - Write out buffer to subsector
1012
1013        if (status == ALT_E_SUCCESS)
1014        {
1015            status = alt_qspi_read_bank(subsec_buf  + subsec_partial_tail,
1016                                        subsec_addr + subsec_partial_tail,
1017                                        ALT_QSPI_SUBSECTOR_SIZE - subsec_partial_tail);
1018        }
1019        if (status == ALT_E_SUCCESS)
1020        {
1021            status = alt_qspi_erase_subsector_bank(subsec_addr);
1022        }
1023        if (status == ALT_E_SUCCESS)
1024        {
1025            memcpy(subsec_buf, src, subsec_partial_tail);
1026            status = alt_qspi_indirect_subsector_aligned_write_helper(subsec_buf, subsec_addr);
1027        }
1028
1029        src  += subsec_partial_tail;
1030        size -= subsec_partial_tail;
1031
1032        dprintf("DEBUG[QSPI]: replace(): partial tail: size left = 0x%x, status = %" PRIi32 ".\n",
1033                size, status);
1034    }
1035
1036    return status;
1037}
1038
1039ALT_STATUS_CODE alt_qspi_replace(uint32_t dst, const void * src, size_t size)
1040{
1041    if (dst >= qspi_device_size)
1042    {
1043        return ALT_E_ERROR;
1044    }
1045
1046    if (dst + size - 1 >= qspi_device_size)
1047    {
1048        return ALT_E_ERROR;
1049    }
1050
1051    if (size == 0)
1052    {
1053        return ALT_E_SUCCESS;
1054    }
1055
1056    if ((uintptr_t)src & 0x3)
1057    {
1058        return ALT_E_ERROR;
1059    }
1060
1061    if (dst & 0x3)
1062    {
1063        return ALT_E_ERROR;
1064    }
1065
1066    if (size & 0x3)
1067    {
1068        return ALT_E_ERROR;
1069    }
1070
1071    /////
1072
1073    // Verify that there is not already a read in progress.
1074    if (ALT_QSPI_INDRD_RD_STAT_GET(alt_read_word(ALT_QSPI_INDRD_ADDR)))
1075    {
1076        return ALT_E_ERROR;
1077    }
1078
1079    // Verify that there is not already a write in progress.
1080    if (ALT_QSPI_INDWR_RDSTAT_GET(alt_read_word(ALT_QSPI_INDWR_ADDR)))
1081    {
1082        return ALT_E_ERROR;
1083    }
1084
1085    /////
1086
1087    ALT_STATUS_CODE status = ALT_E_SUCCESS;
1088
1089    uint32_t bank_count = ((dst + size - 1) >> 24) - (dst >> 24) + 1;
1090    uint32_t bank_addr  = dst & ALT_QSPI_BANK_ADDR_MSK;
1091    uint32_t bank_ofst  = dst & (ALT_QSPI_BANK_SIZE - 1);
1092
1093    const char * data = (const char *)src;
1094
1095    uint32_t copy_length = MIN(size, ALT_QSPI_BANK_SIZE - bank_ofst);
1096
1097    dprintf("DEBUG[QSPI]: replace(): bulk: flash_addr = 0x%" PRIx32 "; mem_addr = %p.\n", dst, data);
1098    dprintf("DEBUG[QSPI]: replace(): bulk: bank_count = 0x%" PRIx32 ", bank_ofst = 0x%" PRIx32 ".\n", bank_count, bank_ofst);
1099
1100    for (uint32_t i = 0; i < bank_count; ++i)
1101    {
1102        dprintf("DEBUG[QSPI]: replace(): bank 0x%" PRIx32 "; copy_length = 0x%" PRIx32 ".\n", bank_addr >> 24, copy_length);
1103
1104        status = alt_qspi_device_bank_select(bank_addr >> 24);
1105        if (status != ALT_E_SUCCESS)
1106        {
1107            break;
1108        }
1109
1110        status = alt_qspi_replace_bank(bank_ofst, data, copy_length);
1111        if (status != ALT_E_SUCCESS)
1112        {
1113            break;
1114        }
1115
1116        bank_addr += ALT_QSPI_BANK_SIZE;
1117        data += copy_length;
1118        size -= copy_length;
1119
1120        copy_length = MIN(size, ALT_QSPI_BANK_SIZE);
1121    }
1122
1123    return status;
1124}
1125
1126/////
1127
1128ALT_QSPI_BAUD_DIV_t alt_qspi_baud_rate_div_get(void)
1129{
1130    uint32_t baud_rate_div = ALT_QSPI_CFG_BAUDDIV_GET(alt_read_word(ALT_QSPI_CFG_ADDR));
1131    return (ALT_QSPI_BAUD_DIV_t) baud_rate_div;
1132}
1133
1134ALT_STATUS_CODE alt_qspi_baud_rate_div_set(const ALT_QSPI_BAUD_DIV_t baud_rate_div)
1135{
1136    if (0xf < (uint32_t)baud_rate_div)
1137    {
1138        // Invalid baud rate divisor value.
1139        return ALT_E_BAD_ARG;
1140    }
1141
1142    // Set the Master Mode Baud Rate Divisor Field of the QSPI Configuration Register.
1143    alt_replbits_word(ALT_QSPI_CFG_ADDR,
1144                      ALT_QSPI_CFG_BAUDDIV_SET_MSK,
1145                      ALT_QSPI_CFG_BAUDDIV_SET(baud_rate_div));
1146
1147    return ALT_E_SUCCESS;
1148}
1149
1150ALT_STATUS_CODE alt_qspi_chip_select_config_get(uint32_t* cs,
1151                                                ALT_QSPI_CS_MODE_t* cs_mode)
1152{
1153    uint32_t cfg = alt_read_word(ALT_QSPI_CFG_ADDR);
1154
1155    *cs      = ALT_QSPI_CFG_PERCSLINES_GET(cfg);
1156    *cs_mode = (ALT_QSPI_CS_MODE_t) ALT_QSPI_CFG_PERSELDEC_GET(cfg);
1157
1158    return ALT_E_SUCCESS;
1159}
1160
1161ALT_STATUS_CODE alt_qspi_chip_select_config_set(const uint32_t cs,
1162                                                const ALT_QSPI_CS_MODE_t cs_mode)
1163{
1164    // chip select cs:
1165    // four bit value, bit 0 = cs0, bit 1 = cs1, bit 2 = cs2, bit 3 = cs3
1166    // since cs is low true, the value of each bit should be zero if enable the cs.
1167    //
1168    // also allows multiple cs line enabled together.
1169 
1170    if (cs > ((1 << ALT_QSPI_CFG_PERCSLINES_WIDTH) - 1))
1171    {
1172        // [cs] not within possible 4 bit chip select line value range.
1173        return ALT_E_ARG_RANGE;
1174    }
1175
1176    if ((cs_mode != ALT_QSPI_CS_MODE_SINGLE_SELECT) && (cs_mode != ALT_QSPI_CS_MODE_DECODE))
1177    {
1178        return ALT_E_INV_OPTION;
1179    }
1180
1181    // Update the Peripheral Chip Select Lines and Peripheral Select Decode
1182    // Fields of the QSPI Configuration Register value with the chip select
1183    // options.
1184    uint32_t cfg = alt_read_word(ALT_QSPI_CFG_ADDR);
1185    cfg &= ALT_QSPI_CFG_PERCSLINES_CLR_MSK & ALT_QSPI_CFG_PERSELDEC_CLR_MSK;
1186    cfg |= ALT_QSPI_CFG_PERCSLINES_SET(cs) | ALT_QSPI_CFG_PERSELDEC_SET(cs_mode);
1187    alt_write_word(ALT_QSPI_CFG_ADDR, cfg);
1188
1189    return ALT_E_SUCCESS;
1190}
1191
1192ALT_STATUS_CODE alt_qspi_mode_bit_disable(void)
1193{
1194    // Clear the Mode Bit Enable Field of the Device Read Instruction Register
1195    // to disable mode bits from being sent after the address bytes.
1196    alt_clrbits_word(ALT_QSPI_DEVRD_ADDR, ALT_QSPI_DEVRD_ENMODBITS_SET_MSK);
1197
1198    return ALT_E_SUCCESS;
1199}
1200
1201ALT_STATUS_CODE alt_qspi_mode_bit_enable(void)
1202{
1203    // Set the Mode Bit Enable Field of the Device Read Instruction Register
1204    // to enable mode bits to be sent after the address bytes.
1205    alt_setbits_word(ALT_QSPI_DEVRD_ADDR, ALT_QSPI_DEVRD_ENMODBITS_SET_MSK);
1206
1207    return ALT_E_SUCCESS;
1208}
1209
1210uint32_t alt_qspi_mode_bit_config_get(void)
1211{
1212    // Return the 8 bit value from the Mode Field of the Mode Bit Configuration
1213    // Register.
1214    return ALT_QSPI_MODBIT_MOD_GET(alt_read_word(ALT_QSPI_MODBIT_ADDR));
1215}
1216
1217ALT_STATUS_CODE alt_qspi_mode_bit_config_set(const uint32_t mode_bits)
1218{
1219    if (alt_qspi_is_idle() == false)
1220    {
1221        return ALT_E_ERROR;
1222    }
1223
1224    if (mode_bits > ((1 << ALT_QSPI_MODBIT_MOD_WIDTH) - 1))
1225    {
1226        // 'mode_bits' not within possible 8 bit mode value range.
1227        return ALT_E_ARG_RANGE;
1228    }
1229
1230    // Set the 8 bit value in the Mode Field of the Mode Bit Configuration
1231    // Register.
1232    alt_replbits_word(ALT_QSPI_MODBIT_ADDR,
1233                      ALT_QSPI_MODBIT_MOD_SET_MSK,
1234                      ALT_QSPI_MODBIT_MOD_SET(mode_bits));
1235
1236    return ALT_E_SUCCESS;
1237}
1238
1239ALT_STATUS_CODE alt_qspi_device_size_config_get(ALT_QSPI_DEV_SIZE_CONFIG_t * cfg)
1240{
1241    // Although not required, it is recommended that the write protect feature
1242    // be enabled prior to enabling the QSPI controller. This will block any AHB
1243    // writes from taking effect. This also means the write protection registers
1244    // (Lower Write Protection, Upper Write Protection, and Write Protection)
1245    // should be setup and the number of bytes per device block in the device
1246    // size configuration register should be setup prior to enabling the QSPI
1247    // controller.
1248
1249    // Read Device Size Register and get the Number of Bytes per Block, Number
1250    // of Bytes per Device, and Number of Address Bytes Fields.
1251
1252    uint32_t devsz = alt_read_word(ALT_QSPI_DEVSZ_ADDR);
1253
1254    cfg->block_size = ALT_QSPI_DEVSZ_BYTESPERSUBSECTOR_GET(devsz);
1255    cfg->page_size  = ALT_QSPI_DEVSZ_BYTESPERDEVICEPAGE_GET(devsz);
1256    cfg->addr_size  = ALT_QSPI_DEVSZ_NUMADDRBYTES_GET(devsz);
1257
1258    // Read Lower Write Protection, Upper Write Protection, and Write Protection
1259    // Registers.
1260
1261    cfg->lower_wrprot_block = ALT_QSPI_LOWWRPROT_SUBSECTOR_GET(alt_read_word(ALT_QSPI_LOWWRPROT_ADDR));
1262    cfg->upper_wrprot_block = ALT_QSPI_UPPWRPROT_SUBSECTOR_GET(alt_read_word(ALT_QSPI_UPPWRPROT_ADDR));
1263    cfg->wrprot_enable      = ALT_QSPI_WRPROT_EN_GET(alt_read_word(ALT_QSPI_WRPROT_ADDR));
1264
1265    return ALT_E_SUCCESS;
1266}
1267
1268ALT_STATUS_CODE alt_qspi_device_size_config_set(const ALT_QSPI_DEV_SIZE_CONFIG_t * cfg)
1269{
1270    if (cfg->block_size > ((1 << ALT_QSPI_DEVSZ_BYTESPERSUBSECTOR_WIDTH) - 1))
1271    {
1272        return ALT_E_ARG_RANGE;
1273    }
1274
1275    if (cfg->page_size > ((1 << ALT_QSPI_DEVSZ_BYTESPERDEVICEPAGE_WIDTH) - 1))
1276    {
1277        return ALT_E_ARG_RANGE;
1278    }
1279
1280    if (cfg->addr_size > ((1 << ALT_QSPI_DEVSZ_NUMADDRBYTES_WIDTH) - 1))
1281    {
1282        return ALT_E_ARG_RANGE;
1283    }
1284
1285    if (cfg->lower_wrprot_block > cfg->upper_wrprot_block)
1286    {
1287        // Null write protection regions are not allowed.
1288        return ALT_E_ARG_RANGE;
1289    }
1290
1291    /////
1292
1293    uint32_t value = ALT_QSPI_DEVSZ_BYTESPERSUBSECTOR_SET(cfg->block_size) |
1294                     ALT_QSPI_DEVSZ_BYTESPERDEVICEPAGE_SET(cfg->page_size) |
1295                     ALT_QSPI_DEVSZ_NUMADDRBYTES_SET(cfg->addr_size);
1296
1297    alt_write_word(ALT_QSPI_DEVSZ_ADDR, value);
1298
1299    if (cfg->wrprot_enable)
1300    {
1301        alt_write_word(ALT_QSPI_LOWWRPROT_ADDR, cfg->lower_wrprot_block);
1302        alt_write_word(ALT_QSPI_UPPWRPROT_ADDR, cfg->upper_wrprot_block);
1303    }
1304
1305    // Read Upper Write Protection Register - uppwrprot.
1306    // Set the Write Protection Enable Bit Field of the Write Protection
1307    // Register accordingly.
1308    if (cfg->wrprot_enable)
1309    {
1310        alt_setbits_word(ALT_QSPI_WRPROT_ADDR, ALT_QSPI_WRPROT_EN_SET(1));
1311    }
1312    else
1313    {
1314        alt_clrbits_word(ALT_QSPI_WRPROT_ADDR, ALT_QSPI_WRPROT_EN_SET(1));
1315    }
1316    return ALT_E_SUCCESS;
1317}
1318
1319ALT_STATUS_CODE alt_qspi_device_read_config_get(ALT_QSPI_DEV_INST_CONFIG_t * cfg)
1320{
1321    // Read the Device Read Instruction Register - devrd.
1322    uint32_t devrd = alt_read_word(ALT_QSPI_DEVRD_ADDR);
1323
1324    cfg->op_code        = ALT_QSPI_DEVRD_RDOPCODE_GET(devrd);
1325    cfg->inst_type      = (ALT_QSPI_MODE_t) ALT_QSPI_DEVRD_INSTWIDTH_GET(devrd);
1326    cfg->addr_xfer_type = (ALT_QSPI_MODE_t) ALT_QSPI_DEVRD_ADDRWIDTH_GET(devrd);
1327    cfg->data_xfer_type = (ALT_QSPI_MODE_t) ALT_QSPI_DEVRD_DATAWIDTH_GET(devrd);
1328    cfg->dummy_cycles   = ALT_QSPI_DEVRD_DUMMYRDCLKS_GET(devrd);
1329
1330    return ALT_E_SUCCESS;
1331}
1332
1333ALT_STATUS_CODE alt_qspi_device_read_config_set(const ALT_QSPI_DEV_INST_CONFIG_t * cfg)
1334{
1335    if (alt_qspi_is_idle() == false)
1336    {
1337        return ALT_E_ERROR;
1338    }
1339
1340    // Validate input
1341
1342    if (cfg->op_code > ((1 << ALT_QSPI_DEVRD_RDOPCODE_WIDTH) - 1))
1343    {
1344        return ALT_E_BAD_ARG;
1345    }
1346
1347    switch (cfg->inst_type)
1348    {
1349    case ALT_QSPI_MODE_SINGLE:
1350    case ALT_QSPI_MODE_DUAL:
1351    case ALT_QSPI_MODE_QUAD:
1352        break;
1353    default:
1354        return ALT_E_BAD_ARG;
1355    }
1356
1357    switch (cfg->addr_xfer_type)
1358    {
1359    case ALT_QSPI_MODE_SINGLE:
1360    case ALT_QSPI_MODE_DUAL:
1361    case ALT_QSPI_MODE_QUAD:
1362        break;
1363    default:
1364        return ALT_E_BAD_ARG;
1365    }
1366
1367    switch (cfg->data_xfer_type)
1368    {
1369    case ALT_QSPI_MODE_SINGLE:
1370    case ALT_QSPI_MODE_DUAL:
1371    case ALT_QSPI_MODE_QUAD:
1372        break;
1373    default:
1374        return ALT_E_BAD_ARG;
1375    }
1376
1377    if (cfg->dummy_cycles > ((1 << ALT_QSPI_DEVRD_DUMMYRDCLKS_WIDTH) - 1))
1378    {
1379        return ALT_E_BAD_ARG;
1380    }
1381
1382    /////
1383
1384    // Read the Device Read Instruction Register - devrd.
1385    uint32_t devrd = alt_read_word(ALT_QSPI_DEVRD_ADDR);
1386
1387    devrd &= ALT_QSPI_DEVRD_RDOPCODE_CLR_MSK &
1388             ALT_QSPI_DEVRD_INSTWIDTH_CLR_MSK &
1389             ALT_QSPI_DEVRD_ADDRWIDTH_CLR_MSK &
1390             ALT_QSPI_DEVRD_DATAWIDTH_CLR_MSK &
1391             ALT_QSPI_DEVRD_DUMMYRDCLKS_CLR_MSK;
1392
1393    devrd |= ALT_QSPI_DEVRD_RDOPCODE_SET(cfg->op_code) |
1394             ALT_QSPI_DEVRD_INSTWIDTH_SET(cfg->inst_type) |
1395             ALT_QSPI_DEVRD_ADDRWIDTH_SET(cfg->addr_xfer_type) |
1396             ALT_QSPI_DEVRD_DATAWIDTH_SET(cfg->data_xfer_type) |
1397             ALT_QSPI_DEVRD_DUMMYRDCLKS_SET(cfg->dummy_cycles);
1398
1399    alt_write_word(ALT_QSPI_DEVRD_ADDR, devrd);
1400
1401    return ALT_E_SUCCESS;
1402}
1403
1404ALT_STATUS_CODE alt_qspi_device_write_config_get(ALT_QSPI_DEV_INST_CONFIG_t * cfg)
1405{
1406    // Device Write Instruction Register - devwr.
1407    uint32_t devwr = alt_read_word(ALT_QSPI_DEVWR_ADDR);
1408
1409    cfg->op_code        = ALT_QSPI_DEVWR_WROPCODE_GET(devwr);
1410    // The Instruction Type field in the Device READ Instruction Register only appears
1411    // once and applies to both READ and WRITE opertions. it is not included in the
1412    // Device WRITE Instruction Register.
1413    cfg->inst_type      = (ALT_QSPI_MODE_t) ALT_QSPI_DEVRD_INSTWIDTH_GET(alt_read_word(ALT_QSPI_DEVRD_ADDR));
1414    cfg->addr_xfer_type = (ALT_QSPI_MODE_t) ALT_QSPI_DEVWR_ADDRWIDTH_GET(devwr);
1415    cfg->data_xfer_type = (ALT_QSPI_MODE_t) ALT_QSPI_DEVWR_DATAWIDTH_GET(devwr);
1416    cfg->dummy_cycles   = ALT_QSPI_DEVWR_DUMMYWRCLKS_GET(devwr);
1417
1418    return ALT_E_SUCCESS;
1419}
1420
1421ALT_STATUS_CODE alt_qspi_device_write_config_set(const ALT_QSPI_DEV_INST_CONFIG_t * cfg)
1422{
1423    if (alt_qspi_is_idle() == false)
1424    {
1425        return ALT_E_ERROR;
1426    }
1427
1428    // Validate input
1429
1430    if (cfg->op_code > ((1 << ALT_QSPI_DEVWR_WROPCODE_WIDTH) - 1))
1431    {
1432        return ALT_E_BAD_ARG;
1433    }
1434
1435    switch (cfg->inst_type)
1436    {
1437    case ALT_QSPI_MODE_SINGLE:
1438    case ALT_QSPI_MODE_DUAL:
1439    case ALT_QSPI_MODE_QUAD:
1440        break;
1441    default:
1442        return ALT_E_BAD_ARG;
1443    }
1444
1445    switch (cfg->addr_xfer_type)
1446    {
1447    case ALT_QSPI_MODE_SINGLE:
1448    case ALT_QSPI_MODE_DUAL:
1449    case ALT_QSPI_MODE_QUAD:
1450        break;
1451    default:
1452        return ALT_E_BAD_ARG;
1453    }
1454
1455    switch (cfg->data_xfer_type)
1456    {
1457    case ALT_QSPI_MODE_SINGLE:
1458    case ALT_QSPI_MODE_DUAL:
1459    case ALT_QSPI_MODE_QUAD:
1460        break;
1461    default:
1462        return ALT_E_BAD_ARG;
1463    }
1464
1465    if (cfg->dummy_cycles > ((1 << ALT_QSPI_DEVWR_DUMMYWRCLKS_WIDTH) - 1))
1466    {
1467        return ALT_E_BAD_ARG;
1468    }
1469
1470    /////
1471
1472    // Read the Device Write Instruction Register - devwr.
1473    uint32_t devwr = alt_read_word(ALT_QSPI_DEVWR_ADDR);
1474
1475    devwr &= ALT_QSPI_DEVWR_WROPCODE_CLR_MSK &
1476             ALT_QSPI_DEVWR_ADDRWIDTH_CLR_MSK &
1477             ALT_QSPI_DEVWR_DATAWIDTH_CLR_MSK &
1478             ALT_QSPI_DEVWR_DUMMYWRCLKS_CLR_MSK;
1479
1480    devwr |= ALT_QSPI_DEVWR_WROPCODE_SET(cfg->op_code) |
1481             ALT_QSPI_DEVWR_ADDRWIDTH_SET(cfg->addr_xfer_type) |
1482             ALT_QSPI_DEVWR_DATAWIDTH_SET(cfg->data_xfer_type) |
1483             ALT_QSPI_DEVWR_DUMMYWRCLKS_SET(cfg->dummy_cycles);
1484
1485    alt_write_word(ALT_QSPI_DEVWR_ADDR, devwr);
1486
1487    // The Instruction Type field in the Device READ Instruction Register only appears
1488    // once and applies to both READ and WRITE operations - it is not included in the
1489    // Device WRITE Instruction Register. Therefore, modify the Instruction Type
1490    // Field in the Device Read Register.
1491    alt_replbits_word(ALT_QSPI_DEVRD_ADDR,
1492                      ALT_QSPI_DEVRD_INSTWIDTH_SET_MSK,
1493                      ALT_QSPI_DEVRD_INSTWIDTH_SET((uint32_t) cfg->inst_type));
1494
1495    return ALT_E_SUCCESS;
1496}
1497
1498ALT_STATUS_CODE alt_qspi_timing_config_get(ALT_QSPI_TIMING_CONFIG_t * cfg)
1499{
1500    // QSPI Configuration Register - cfg
1501    uint32_t cfgreg = alt_read_word(ALT_QSPI_CFG_ADDR);
1502    cfg->clk_phase  = (ALT_QSPI_CLK_PHASE_t) ALT_QSPI_CFG_SELCLKPHASE_GET(cfgreg);
1503    cfg->clk_pol    = (ALT_QSPI_CLK_POLARITY_t) ALT_QSPI_CFG_SELCLKPOL_GET(cfgreg);
1504
1505    // QSPI Device Delay Register
1506    uint32_t delayreg = alt_read_word(ALT_QSPI_DELAY_ADDR);
1507    cfg->cs_sot  = ALT_QSPI_DELAY_INIT_GET(delayreg);
1508    cfg->cs_eot  = ALT_QSPI_DELAY_AFTER_GET(delayreg);
1509    cfg->cs_dads = ALT_QSPI_DELAY_BTWN_GET(delayreg);
1510    cfg->cs_da   = ALT_QSPI_DELAY_NSS_GET(delayreg);
1511
1512    // Read Data Capture Register
1513    cfg->rd_datacap = ALT_QSPI_RDDATACAP_DELAY_GET(alt_read_word(ALT_QSPI_RDDATACAP_ADDR));
1514
1515    return ALT_E_SUCCESS;
1516}
1517
1518ALT_STATUS_CODE alt_qspi_timing_config_set(const ALT_QSPI_TIMING_CONFIG_t * cfg)
1519{
1520    if (alt_qspi_is_idle() == false)
1521    {
1522        return ALT_E_ERROR;
1523    }
1524
1525    // Validate parameter(s)
1526
1527    switch (cfg->clk_phase)
1528    {
1529    case ALT_QSPI_CLK_PHASE_ACTIVE:
1530    case ALT_QSPI_CLK_PHASE_INACTIVE:
1531        break;
1532    default:
1533        return ALT_E_BAD_ARG;
1534    }
1535
1536    switch (cfg->clk_pol)
1537    {
1538    case ALT_QSPI_CLK_POLARITY_LOW:
1539    case ALT_QSPI_CLK_POLARITY_HIGH:
1540        break;
1541    default:
1542        return ALT_E_BAD_ARG;
1543    }
1544
1545    if (cfg->cs_da > ((1 << ALT_QSPI_DELAY_NSS_WIDTH) - 1))
1546    {
1547        return ALT_E_BAD_ARG;
1548    }
1549    if (cfg->cs_dads > ((1 << ALT_QSPI_DELAY_BTWN_WIDTH) - 1))
1550    {
1551        return ALT_E_BAD_ARG;
1552    }
1553    if (cfg->cs_eot > ((1 << ALT_QSPI_DELAY_AFTER_WIDTH) - 1))
1554    {
1555        return ALT_E_BAD_ARG;
1556    }
1557    if (cfg->cs_sot > ((1 << ALT_QSPI_DELAY_INIT_WIDTH) - 1))
1558    {
1559        return ALT_E_BAD_ARG;
1560    }
1561
1562    if (cfg->rd_datacap > ((1 << ALT_QSPI_RDDATACAP_DELAY_WIDTH) - 1))
1563    {
1564        return ALT_E_BAD_ARG;
1565    }
1566
1567    /////
1568
1569    // QSPI Configuration Register - cfg
1570    uint32_t cfgreg = alt_read_word(ALT_QSPI_CFG_ADDR);
1571    cfgreg &= ALT_QSPI_CFG_SELCLKPHASE_CLR_MSK &
1572              ALT_QSPI_CFG_SELCLKPOL_CLR_MSK;
1573    cfgreg |= ALT_QSPI_CFG_SELCLKPHASE_SET(cfg->clk_phase) |
1574              ALT_QSPI_CFG_SELCLKPOL_SET(cfg->clk_pol);
1575    alt_write_word(ALT_QSPI_CFG_ADDR, cfgreg);
1576
1577    // QSPI Device Delay Register
1578    uint32_t delayreg = ALT_QSPI_DELAY_INIT_SET(cfg->cs_sot)  |
1579                        ALT_QSPI_DELAY_AFTER_SET(cfg->cs_eot) |
1580                        ALT_QSPI_DELAY_BTWN_SET(cfg->cs_dads) |
1581                        ALT_QSPI_DELAY_NSS_SET(cfg->cs_da);
1582    alt_write_word(ALT_QSPI_DELAY_ADDR, delayreg);
1583
1584    // Read Data Capture Register
1585
1586    alt_write_word(ALT_QSPI_RDDATACAP_ADDR,
1587                   ALT_QSPI_RDDATACAP_BYP_SET(1) | 
1588                   ALT_QSPI_RDDATACAP_DELAY_SET(cfg->rd_datacap));
1589
1590    return ALT_E_SUCCESS;
1591}
1592
1593/////
1594
1595ALT_STATUS_CODE alt_qspi_direct_disable(void)
1596{
1597    // Clear (set to 0) the Enable Direct Access Controller Field of the QSPI
1598    // Configuration Register to disable the Direct Access Controller.
1599    alt_clrbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENDIRACC_SET_MSK);
1600
1601    return ALT_E_SUCCESS;
1602}
1603
1604ALT_STATUS_CODE alt_qspi_direct_enable(void)
1605{
1606    // Set (set to 1) the Enable Direct Access Controller Field of the QSPI
1607    // Configuration Register to enable the Direct Access Controller.
1608    alt_setbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENDIRACC_SET_MSK);
1609
1610    return ALT_E_SUCCESS;
1611}
1612
1613uint32_t alt_qspi_ahb_remap_address_get(void)
1614{
1615    // Read and return the value of the Remap Address Register.
1616    return ALT_QSPI_REMAPADDR_VALUE_GET(alt_read_word(ALT_QSPI_REMAPADDR_ADDR));
1617}
1618
1619ALT_STATUS_CODE alt_qspi_ahb_remap_address_set(const uint32_t ahb_remap_addr)
1620{
1621    if (alt_qspi_is_idle() == false)
1622    {
1623        return ALT_E_ERROR;
1624    }
1625
1626    // Read and return the value of the Remap Address Register.
1627    alt_setbits_word(ALT_QSPI_REMAPADDR_ADDR, ALT_QSPI_REMAPADDR_VALUE_SET(ahb_remap_addr));
1628
1629    return ALT_E_SUCCESS;
1630}
1631
1632ALT_STATUS_CODE alt_qspi_ahb_address_remap_disable(void)
1633{
1634    // Clear (set to 0) the Enable AHB Address Remapping Field of the QSPI
1635    // Configuration Register to disable AHB address remapping.
1636    alt_clrbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENAHBREMAP_SET_MSK);
1637
1638    return ALT_E_SUCCESS;
1639}
1640
1641ALT_STATUS_CODE alt_qspi_ahb_address_remap_enable(void)
1642{
1643    // Set (set to 1) the Enable AHB Address Remapping Field of the QSPI
1644    // Configuration Register to enable AHB address remapping.
1645    alt_setbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENAHBREMAP_SET_MSK);
1646
1647    return ALT_E_SUCCESS;
1648}
1649
1650/////
1651
1652static ALT_STATUS_CODE alt_qspi_indirect_read_start_bank(uint32_t flash_addr,
1653                                                         size_t num_bytes)
1654{
1655    alt_write_word(ALT_QSPI_INDRDSTADDR_ADDR, flash_addr);
1656    alt_write_word(ALT_QSPI_INDRDCNT_ADDR, num_bytes);
1657    alt_write_word(ALT_QSPI_INDRD_ADDR, ALT_QSPI_INDRD_START_SET_MSK |
1658                                        ALT_QSPI_INDRD_IND_OPS_DONE_STAT_SET_MSK);
1659
1660    return ALT_E_SUCCESS;
1661}
1662
1663ALT_STATUS_CODE alt_qspi_indirect_read_start(const uint32_t flash_addr,
1664                                             const size_t num_bytes)
1665{
1666    // flash_addr and num_bytes restriction is to prevent possible unaligned
1667    // exceptions.
1668
1669    if (flash_addr & 0x3)
1670    {
1671        return ALT_E_ERROR;
1672    }
1673
1674    if (num_bytes & 0x3)
1675    {
1676        return ALT_E_ERROR;
1677    }
1678
1679    if (num_bytes == 0)
1680    {
1681        // Do not report this as a success. If a indirect read was not
1682        // previously completed, it may be cleared already, at which point
1683        // alt_qspi_indirect_read_is_complete() will never report true.
1684        return ALT_E_ERROR;
1685    }
1686
1687    if (flash_addr > qspi_device_size)
1688    {
1689        return ALT_E_ERROR;
1690    }
1691
1692    if (flash_addr + num_bytes > qspi_device_size)
1693    {
1694        return ALT_E_ERROR;
1695    }
1696
1697    // Verify request does not cross bank boundary.
1698    // This limitation is due to the 3-byte addressing limitation.
1699    if ((flash_addr & ALT_QSPI_BANK_ADDR_MSK) != ((flash_addr + num_bytes - 1) & ALT_QSPI_BANK_ADDR_MSK))
1700    {
1701        return ALT_E_ERROR;
1702    }
1703
1704    // Verify that there is not already a read in progress.
1705    if (ALT_QSPI_INDRD_RD_STAT_GET(alt_read_word(ALT_QSPI_INDRD_ADDR)))
1706    {
1707        return ALT_E_ERROR;
1708    }
1709
1710    /////
1711
1712    ALT_STATUS_CODE status;
1713    status = alt_qspi_device_bank_select(flash_addr >> 24);
1714    if (status != ALT_E_SUCCESS)
1715    {
1716        return status;
1717    }
1718
1719    /////
1720
1721    return alt_qspi_indirect_read_start_bank(flash_addr,
1722                                             num_bytes);
1723
1724}
1725
1726ALT_STATUS_CODE alt_qspi_indirect_read_finish(void)
1727{
1728    return ALT_E_SUCCESS;
1729}
1730
1731ALT_STATUS_CODE alt_qspi_indirect_read_cancel(void)
1732{
1733    // An indirect operation may be cancelled at any time by setting Indirect
1734    // Transfer Control Register bit [1].
1735    alt_write_word(ALT_QSPI_INDRD_ADDR, ALT_QSPI_INDRD_CANCEL_SET_MSK);
1736
1737    return ALT_E_SUCCESS;
1738}
1739
1740uint32_t alt_qspi_indirect_read_fill_level(void)
1741{
1742    // Return the SRAM Fill Level (Indirect Read Partition) Field of the SRAM
1743    // Fill Register to get the SRAM Fill Level for the Indirect Read Partition
1744    // in units of SRAM Words (4 bytes).
1745    return ALT_QSPI_SRAMFILL_INDRDPART_GET(alt_read_word(ALT_QSPI_SRAMFILL_ADDR));
1746}
1747
1748uint32_t alt_qspi_indirect_read_watermark_get(void)
1749{
1750    // Return the Watermark value in the Indirect Read Transfer Watermark Register.
1751    return alt_read_word(ALT_QSPI_INDRDWATER_ADDR);
1752}
1753
1754ALT_STATUS_CODE alt_qspi_indirect_read_watermark_set(const uint32_t watermark)
1755{
1756    // Verify that there is not already a read in progress.
1757    if (ALT_QSPI_INDRD_RD_STAT_GET(alt_read_word(ALT_QSPI_INDRD_ADDR)))
1758    {
1759        return ALT_E_ERROR;
1760    }
1761
1762    // Set the Watermark value in the Indirect Read Transfer Watermark Register.
1763    alt_write_word(ALT_QSPI_INDRDWATER_ADDR, watermark);
1764
1765    return ALT_E_SUCCESS;
1766}
1767
1768bool alt_qspi_indirect_read_is_complete(void)
1769{
1770    // The value of the Indirect Completion Status Field of the Indirect Read
1771    // Transfer Control Register is set by hardware when an indirect read
1772    // operation has completed.
1773    return (alt_read_word(ALT_QSPI_INDRD_ADDR) & ALT_QSPI_INDRD_IND_OPS_DONE_STAT_SET_MSK) != 0;
1774}
1775
1776static ALT_STATUS_CODE alt_qspi_indirect_write_start_bank(uint32_t flash_addr,
1777                                                          size_t num_bytes)
1778{
1779    alt_write_word(ALT_QSPI_INDWRSTADDR_ADDR, flash_addr);
1780    alt_write_word(ALT_QSPI_INDWRCNT_ADDR, num_bytes);
1781    alt_write_word(ALT_QSPI_INDWR_ADDR, ALT_QSPI_INDWR_START_SET_MSK |
1782                                        ALT_QSPI_INDWR_INDDONE_SET_MSK);
1783
1784    return ALT_E_SUCCESS;
1785}
1786
1787ALT_STATUS_CODE alt_qspi_indirect_write_start(const uint32_t flash_addr,
1788                                              const size_t num_bytes)
1789{
1790    // flash_addr and num_bytes restriction is to prevent possible unaligned
1791    // exceptions.
1792
1793    if (flash_addr & 0x3)
1794    {
1795        return ALT_E_ERROR;
1796    }
1797
1798    if (num_bytes & 0x3)
1799    {
1800        return ALT_E_ERROR;
1801    }
1802
1803    if (num_bytes == 0)
1804    {
1805        // Do not report this as a success. If a indirect write was not
1806        // previously completed, it may be cleared already, at which point
1807        // alt_qspi_indirect_write_is_complete() will never report true.
1808        return ALT_E_ERROR;
1809    }
1810
1811    if (num_bytes > 256)
1812    {
1813        // The Micron part can only write up to 256 bytes at a time.
1814        return ALT_E_ERROR;
1815    }
1816
1817    if (flash_addr > qspi_device_size)
1818    {
1819        return ALT_E_ERROR;
1820    }
1821
1822    if (flash_addr + num_bytes > qspi_device_size)
1823    {
1824        return ALT_E_ERROR;
1825    }
1826
1827/*
1828    // Verify request does not cross bank boundary.
1829    // This limitation is due to the 3-byte addressing limitation.
1830    if ((flash_addr & ALT_QSPI_BANK_ADDR_MSK) != ((flash_addr + num_bytes - 1) & ALT_QSPI_BANK_ADDR_MSK))
1831    {
1832        return ALT_E_ERROR;
1833    }
1834*/
1835    // Verify request does not cross page boundary.
1836    // This limitation is in place for the Micron part used.
1837    if ((flash_addr & ALT_QSPI_PAGE_ADDR_MSK) != ((flash_addr + num_bytes - 1) & ALT_QSPI_PAGE_ADDR_MSK))
1838    {
1839        return ALT_E_ERROR;
1840    }
1841
1842    // Verify that there is not already a write in progress.
1843    if (ALT_QSPI_INDWR_RDSTAT_GET(alt_read_word(ALT_QSPI_INDWR_ADDR)))
1844    {
1845        return ALT_E_ERROR;
1846    }
1847
1848    /////
1849
1850    ALT_STATUS_CODE status = ALT_E_SUCCESS;
1851    status = alt_qspi_device_bank_select(flash_addr >> 24);
1852    if (status != ALT_E_SUCCESS)
1853    {
1854        return status;
1855    }
1856
1857    /////
1858
1859    return alt_qspi_indirect_write_start_bank(flash_addr,
1860                                              num_bytes);
1861}
1862
1863ALT_STATUS_CODE alt_qspi_indirect_write_finish(void)
1864{
1865#if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
1866    return alt_qspi_N25Q_flag_wait_for_program(ALT_QSPI_TIMEOUT_INFINITE);
1867#else
1868    return ALT_E_SUCCESS;
1869#endif
1870}
1871
1872ALT_STATUS_CODE alt_qspi_indirect_write_cancel(void)
1873{
1874    ALT_STATUS_CODE status = ALT_E_SUCCESS;
1875
1876#if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
1877    if (status == ALT_E_SUCCESS)
1878    {
1879        status = alt_qspi_N25Q_flag_wait_for_program(ALT_QSPI_TIMEOUT_INFINITE);
1880    }
1881#endif
1882
1883    if (status == ALT_E_SUCCESS)
1884    {
1885        // An indirect operation may be cancelled at any time by setting Indirect
1886        // Transfer Control Register bit [1].
1887        alt_write_word(ALT_QSPI_INDWR_ADDR, ALT_QSPI_INDWR_CANCEL_SET_MSK);
1888    }
1889
1890    return status;
1891}
1892
1893uint32_t alt_qspi_indirect_write_fill_level(void)
1894{
1895    // Return the SRAM Fill Level (Indirect Write Partition) Field of the SRAM
1896    // Fill Register to get the SRAM Fill Level for the Indirect Write Partition
1897    // in units of SRAM Words (4 bytes).
1898    return ALT_QSPI_SRAMFILL_INDWRPART_GET(alt_read_word(ALT_QSPI_SRAMFILL_ADDR));
1899}
1900
1901uint32_t alt_qspi_indirect_write_watermark_get(void)
1902{
1903    // Return the Watermark value in the Indirect Write Transfer Watermark Register.
1904    return alt_read_word(ALT_QSPI_INDWRWATER_ADDR);
1905}
1906
1907ALT_STATUS_CODE alt_qspi_indirect_write_watermark_set(const uint32_t watermark)
1908{
1909    // Verify that there is not already a write in progress.
1910    if (ALT_QSPI_INDWR_RDSTAT_GET(alt_read_word(ALT_QSPI_INDWR_ADDR)))
1911    {
1912        return ALT_E_ERROR;
1913    }
1914
1915    // Set the Watermark value in the Indirect Write Transfer Watermark Register.
1916    alt_write_word(ALT_QSPI_INDWRWATER_ADDR, watermark);
1917
1918    return ALT_E_SUCCESS;
1919}
1920
1921bool alt_qspi_indirect_write_is_complete(void)
1922{
1923    // The value of the Indirect Completion Status Field of the Indirect Write
1924    // Transfer Control Register is set by hardware when an indirect write
1925    // operation has completed.
1926    return (alt_read_word(ALT_QSPI_INDWR_ADDR) & ALT_QSPI_INDWR_INDDONE_SET_MSK) != 0;
1927}
1928
1929/////
1930
1931uint32_t alt_qspi_sram_partition_get(void)
1932{
1933    // The number of locations allocated to indirect read is equal to the value
1934    // of the SRAM partition register. See the documentation for this function
1935    // regarding the + 1 in the IP documentation. This way the get() and set()
1936    // will be symmetrical.
1937
1938    return ALT_QSPI_SRAMPART_ADDR_GET(alt_read_word(ALT_QSPI_SRAMPART_ADDR));
1939}
1940
1941ALT_STATUS_CODE alt_qspi_sram_partition_set(const uint32_t read_part_size)
1942{
1943    if (read_part_size > ((1 << ALT_QSPI_SRAMPART_ADDR_WIDTH) - 1))
1944    {
1945        return ALT_E_ARG_RANGE;
1946    }
1947
1948    alt_replbits_word(ALT_QSPI_SRAMPART_ADDR,
1949                      ALT_QSPI_SRAMPART_ADDR_SET_MSK,
1950                      ALT_QSPI_SRAMPART_ADDR_SET(read_part_size));
1951
1952    return ALT_E_SUCCESS;
1953}
1954
1955/////
1956
1957
1958static ALT_STATUS_CODE alt_qspi_erase_subsector_bank(uint32_t addr)
1959{
1960    ALT_STATUS_CODE status = ALT_E_SUCCESS;
1961
1962    if (status == ALT_E_SUCCESS)
1963    {
1964        status = alt_qspi_device_wren();
1965    }
1966   
1967    if (status == ALT_E_SUCCESS)
1968    {
1969        status = alt_qspi_stig_addr_cmd(ALT_QSPI_STIG_OPCODE_SUBSEC_ERASE, 0, addr, 10000);
1970    }
1971
1972#if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
1973    if (status == ALT_E_SUCCESS)
1974    {
1975        status = alt_qspi_N25Q_flag_wait_for_erase(ALT_QSPI_TIMEOUT_INFINITE);
1976    }
1977#endif
1978
1979    return status;
1980}
1981
1982ALT_STATUS_CODE alt_qspi_erase_subsector(const uint32_t addr)
1983{
1984    ALT_STATUS_CODE status = ALT_E_SUCCESS;
1985
1986    if (status == ALT_E_SUCCESS)
1987    {
1988        status = alt_qspi_device_bank_select(addr >> 24);
1989    }
1990
1991    if (status == ALT_E_SUCCESS)
1992    {
1993        status = alt_qspi_erase_subsector_bank(addr);
1994    }
1995
1996    return status;
1997}
1998
1999ALT_STATUS_CODE alt_qspi_erase_sector(const uint32_t addr)
2000{
2001    ALT_STATUS_CODE status = ALT_E_SUCCESS;
2002
2003    if (status == ALT_E_SUCCESS)
2004    {
2005        status = alt_qspi_device_bank_select(addr >> 24);
2006    }
2007
2008    if (status == ALT_E_SUCCESS)
2009    {
2010        status = alt_qspi_device_wren();
2011    }
2012
2013    if (status == ALT_E_SUCCESS)
2014    {
2015        status = alt_qspi_stig_addr_cmd(ALT_QSPI_STIG_OPCODE_SEC_ERASE, 0, addr, ALT_QSPI_TIMEOUT_INFINITE);
2016    }
2017
2018#if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
2019    if (status == ALT_E_SUCCESS)
2020    {
2021        status = alt_qspi_N25Q_flag_wait_for_erase(ALT_QSPI_TIMEOUT_INFINITE);
2022    }
2023#endif
2024
2025    return status;
2026}
2027
2028ALT_STATUS_CODE alt_qspi_erase_chip(void)
2029{
2030    ALT_STATUS_CODE status = ALT_E_SUCCESS;
2031
2032    if (qspi_device_size >= (2 * ALT_QSPI_N25Q_DIE_SIZE))
2033    {
2034        // NOTE: This path is specifically for 512 Mib and 1 Gib Micron N25Q
2035        //   chips only.
2036
2037        dprintf("DEBUG[QSPI]: erase[chip]: FYI, wait time is ~800s for 128 MiB.\n");
2038
2039        uint32_t die_count = qspi_device_size / ALT_QSPI_N25Q_DIE_SIZE;
2040
2041        for (int i = 0; i < die_count; ++i)
2042        {
2043            if (status != ALT_E_SUCCESS)
2044            {
2045                break;
2046            }
2047
2048            dprintf("DEBUG[QSPI]: Erase chip: die = %d, total = %" PRIu32 ".\n", i, die_count);
2049
2050            if (status == ALT_E_SUCCESS)
2051            {
2052                status = alt_qspi_device_bank_select(i * (ALT_QSPI_N25Q_DIE_SIZE / ALT_QSPI_BANK_SIZE));
2053            }
2054
2055            if (status == ALT_E_SUCCESS)
2056            {
2057                status = alt_qspi_device_wren(); 
2058            }
2059
2060            if (status == ALT_E_SUCCESS)
2061            {
2062                status = alt_qspi_stig_addr_cmd(ALT_QSPI_STIG_OPCODE_DIE_ERASE, 0,
2063                                                i * ALT_QSPI_N25Q_DIE_SIZE,
2064                                                ALT_QSPI_TIMEOUT_INFINITE);
2065            }
2066
2067#if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
2068            if (status == ALT_E_SUCCESS)
2069            {
2070                status = alt_qspi_N25Q_flag_wait_for_erase(ALT_QSPI_TIMEOUT_INFINITE);
2071            }
2072#endif
2073        }
2074    }
2075    else
2076    {
2077        // NOTE: Untested path.
2078
2079        dprintf("DEBUG[QSPI]: Bulk erase.\n");
2080
2081        if (status == ALT_E_SUCCESS)
2082        {
2083            status = alt_qspi_device_bank_select(0);
2084        }
2085
2086        if (status == ALT_E_SUCCESS)
2087        {
2088            status = alt_qspi_device_wren();
2089        }
2090
2091        if (status == ALT_E_SUCCESS)
2092        {
2093            // If BULK_ERASE is like other ERASE, it needs the address command.
2094            status = alt_qspi_stig_addr_cmd(ALT_QSPI_STIG_OPCODE_BULK_ERASE, 0,
2095                                            0,
2096                                            ALT_QSPI_TIMEOUT_INFINITE);
2097        }
2098
2099#if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
2100        if (status == ALT_E_SUCCESS)
2101        {
2102            status = alt_qspi_N25Q_flag_wait_for_erase(ALT_QSPI_TIMEOUT_INFINITE);
2103        }
2104#endif
2105    }
2106
2107    return status;
2108}
2109
2110/////
2111
2112ALT_STATUS_CODE alt_qspi_dma_disable(void)
2113{
2114    // Clear (set to 0) the Enable DMA Peripheral Interface Field of the QSPI
2115    // Configuration Register to disable the DMA peripheral interface.
2116    alt_clrbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENDMA_SET_MSK);
2117
2118    return ALT_E_SUCCESS;
2119}
2120
2121ALT_STATUS_CODE alt_qspi_dma_enable(void)
2122{
2123    // Set (set to 1) the Enable DMA Peripheral Interface Field of the QSPI
2124    // Configuration Register to enable the DMA peripheral interface.
2125    alt_setbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENDMA_SET_MSK);
2126
2127    return ALT_E_SUCCESS;
2128}
2129
2130ALT_STATUS_CODE alt_qspi_dma_config_get(uint32_t * single_type_sz,
2131                                        uint32_t * burst_type_sz)
2132{
2133    // Get the current value of the DMA Peripheral Register - dmaper
2134    uint32_t dmaper = alt_read_word(ALT_QSPI_DMAPER_ADDR);
2135
2136    // For both values, a programmed value of 0 represents a single byte. The
2137    // actual number of bytes used is 2 ** (value in this register field).
2138    *single_type_sz = 1 << ALT_QSPI_DMAPER_NUMSGLREQBYTES_GET(dmaper);
2139    *burst_type_sz  = 1 << ALT_QSPI_DMAPER_NUMBURSTREQBYTES_GET(dmaper);
2140
2141    return ALT_E_SUCCESS;
2142}
2143
2144//
2145// Returns true if [n] is a power of 2 value otherwise returns false.
2146//
2147static bool is_pow_2(uint32_t n)
2148{
2149    return ((n > 0) && ((n & (n - 1)) == 0));
2150}
2151
2152//
2153// Return the log base 2 value of a number that is known to be a power of 2.
2154//
2155static uint32_t log2u(uint32_t value)
2156{
2157    uint32_t exp = 0;
2158    while ((exp < 32) && (value != (1 << exp)))
2159    {
2160        ++exp;
2161    }
2162    return exp;
2163}
2164
2165ALT_STATUS_CODE alt_qspi_dma_config_set(const uint32_t single_type_sz,
2166                                        const uint32_t burst_type_sz)
2167{
2168    if (alt_qspi_is_idle() == false)
2169    {
2170        return ALT_E_ERROR;
2171    }
2172
2173    if (single_type_sz < 4)
2174    {
2175        return ALT_E_ERROR;
2176    }
2177
2178    if (burst_type_sz < 4)
2179    {
2180        return ALT_E_ERROR;
2181    }
2182
2183    if (burst_type_sz < single_type_sz)
2184    {
2185        return ALT_E_ERROR;
2186    }
2187
2188    const uint32_t single_type_sz_max = 1 << ((1 << ALT_QSPI_DMAPER_NUMSGLREQBYTES_WIDTH) - 1);
2189    const uint32_t burst_type_sz_max  = 1 << ((1 << ALT_QSPI_DMAPER_NUMBURSTREQBYTES_WIDTH) - 1);
2190
2191    // Both parameter values must be a power of 2 between 1 and 32728.
2192    if (  (single_type_sz > single_type_sz_max) || !is_pow_2(single_type_sz)
2193       || (burst_type_sz  > burst_type_sz_max)  || !is_pow_2(burst_type_sz)
2194       )
2195    {
2196        return ALT_E_ARG_RANGE;
2197    }
2198
2199    // Get the current value of the DMA Peripheral Register - dmaper
2200    uint32_t dmaper = alt_read_word(ALT_QSPI_DMAPER_ADDR);
2201    dmaper &= ALT_QSPI_DMAPER_NUMBURSTREQBYTES_CLR_MSK &
2202              ALT_QSPI_DMAPER_NUMSGLREQBYTES_CLR_MSK;
2203    dmaper |= ALT_QSPI_DMAPER_NUMBURSTREQBYTES_SET(log2u(burst_type_sz)) |
2204              ALT_QSPI_DMAPER_NUMSGLREQBYTES_SET(log2u(single_type_sz));
2205    alt_write_word(ALT_QSPI_DMAPER_ADDR, dmaper);
2206
2207    return ALT_E_SUCCESS;
2208}
2209
2210/////
2211
2212//
2213// Private STIG and device commands
2214//
2215
2216static ALT_STATUS_CODE alt_qspi_stig_cmd_helper(uint32_t reg_value, uint32_t timeout)
2217{
2218    ALT_STATUS_CODE status = ALT_E_SUCCESS;
2219    bool infinite = (timeout == ALT_QSPI_TIMEOUT_INFINITE);
2220
2221    alt_write_word(ALT_QSPI_FLSHCMD_ADDR, reg_value);
2222    alt_write_word(ALT_QSPI_FLSHCMD_ADDR, reg_value | ALT_QSPI_FLSHCMD_EXECCMD_E_EXECUTE);
2223
2224    do
2225    {
2226        reg_value = alt_read_word(ALT_QSPI_FLSHCMD_ADDR);
2227        if (!(reg_value & ALT_QSPI_FLSHCMD_CMDEXECSTAT_SET_MSK))
2228        {
2229            break;
2230        }
2231
2232    } while (timeout-- || infinite);
2233
2234    if (timeout == (uint32_t)-1 && !infinite)
2235    {
2236        status = ALT_E_TMO;
2237    }
2238
2239    return status;
2240}
2241
2242ALT_STATUS_CODE alt_qspi_stig_cmd(uint32_t opcode, uint32_t dummy, uint32_t timeout)
2243{
2244    if (dummy > ((1 << ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_WIDTH) - 1))
2245    {
2246        return ALT_E_ERROR;
2247    }
2248
2249    uint32_t reg = ALT_QSPI_FLSHCMD_CMDOPCODE_SET(opcode) |
2250                   ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_SET(dummy);
2251
2252    return alt_qspi_stig_cmd_helper(reg, timeout);
2253}
2254
2255ALT_STATUS_CODE alt_qspi_stig_rd_cmd(uint8_t opcode,
2256                                     uint32_t dummy,
2257                                     uint32_t num_bytes,
2258                                     uint32_t * output,
2259                                     uint32_t timeout)
2260{
2261    if (dummy > ((1 << ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_WIDTH) - 1))
2262    {
2263        return ALT_E_ERROR;
2264    }
2265
2266    // STIG read can only return up to 8 bytes.
2267    if ((num_bytes > 8) || (num_bytes == 0))
2268    {
2269        return ALT_E_BAD_ARG;
2270    }
2271
2272    uint32_t reg_value = 
2273        ALT_QSPI_FLSHCMD_CMDOPCODE_SET(opcode)                              |
2274        ALT_QSPI_FLSHCMD_ENRDDATA_SET(ALT_QSPI_FLSHCMD_ENRDDATA_E_EN)       |
2275        ALT_QSPI_FLSHCMD_NUMRDDATABYTES_SET(num_bytes - 1)                  |
2276        ALT_QSPI_FLSHCMD_ENCMDADDR_SET(ALT_QSPI_FLSHCMD_ENCMDADDR_E_DISD)   |
2277        ALT_QSPI_FLSHCMD_ENMODBIT_SET(ALT_QSPI_FLSHCMD_ENMODBIT_E_DISD)     |
2278        ALT_QSPI_FLSHCMD_NUMADDRBYTES_SET(0)                                |
2279        ALT_QSPI_FLSHCMD_ENWRDATA_SET(ALT_QSPI_FLSHCMD_ENWRDATA_E_NOACTION) |
2280        ALT_QSPI_FLSHCMD_NUMWRDATABYTES_SET(0)                              |
2281        ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_SET(dummy);
2282
2283    ALT_STATUS_CODE status = ALT_E_SUCCESS;
2284
2285    status = alt_qspi_stig_cmd_helper(reg_value, timeout);
2286    if (status != ALT_E_SUCCESS)
2287    {
2288        return status;
2289    }
2290
2291    output[0] = alt_read_word(ALT_QSPI_FLSHCMDRDDATALO_ADDR);
2292
2293    if (num_bytes > 4)
2294    {
2295        output[1] = alt_read_word(ALT_QSPI_FLSHCMDRDDATAUP_ADDR);
2296    }
2297
2298    return ALT_E_SUCCESS;
2299}
2300
2301ALT_STATUS_CODE alt_qspi_stig_wr_cmd(uint8_t opcode,
2302                                     uint32_t dummy,
2303                                     uint32_t num_bytes, 
2304                                     const uint32_t * input,
2305                                     uint32_t timeout)
2306{
2307    if (dummy > ((1 << ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_WIDTH) - 1))
2308    {
2309        return ALT_E_ERROR;
2310    }
2311
2312    // STIG can only write up to 8 bytes.
2313    if ((num_bytes > 8) || (num_bytes == 0))
2314    {
2315        return ALT_E_BAD_ARG;
2316    }
2317
2318    uint32_t reg_value =
2319        ALT_QSPI_FLSHCMD_CMDOPCODE_SET(opcode)                                 |
2320        ALT_QSPI_FLSHCMD_ENRDDATA_SET(ALT_QSPI_FLSHCMD_ENRDDATA_E_NOACTION)    |
2321        ALT_QSPI_FLSHCMD_NUMRDDATABYTES_SET(0)                                 |
2322        ALT_QSPI_FLSHCMD_ENCMDADDR_SET(ALT_QSPI_FLSHCMD_ENCMDADDR_E_DISD)      |
2323        ALT_QSPI_FLSHCMD_ENMODBIT_SET(ALT_QSPI_FLSHCMD_ENMODBIT_E_DISD)        |
2324        ALT_QSPI_FLSHCMD_NUMADDRBYTES_SET(0)                                   |
2325        ALT_QSPI_FLSHCMD_ENWRDATA_SET(ALT_QSPI_FLSHCMD_ENWRDATA_E_WRDATABYTES) |
2326        ALT_QSPI_FLSHCMD_NUMWRDATABYTES_SET(num_bytes - 1)                     |
2327        ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_SET(dummy);
2328
2329    alt_write_word(ALT_QSPI_FLSHCMDWRDATALO_ADDR, input[0]);
2330
2331    if (num_bytes > 4)
2332    {
2333        alt_write_word(ALT_QSPI_FLSHCMDWRDATAUP_ADDR, input[1]);
2334    }
2335
2336    return alt_qspi_stig_cmd_helper(reg_value, timeout);
2337}
2338
2339ALT_STATUS_CODE alt_qspi_stig_addr_cmd(uint8_t opcode,
2340                                       uint32_t dummy,
2341                                       uint32_t address,
2342                                       uint32_t timeout)
2343{
2344    if (dummy > ((1 << ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_WIDTH) - 1))
2345    {
2346        return ALT_E_ERROR;
2347    }
2348
2349    uint32_t reg = ALT_QSPI_FLSHCMD_CMDOPCODE_SET(opcode) |
2350                   ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_SET(dummy);
2351
2352    reg |= ALT_QSPI_FLSHCMD_ENCMDADDR_SET(ALT_QSPI_FLSHCMD_ENCMDADDR_E_END);
2353    reg |= ALT_QSPI_FLSHCMD_NUMADDRBYTES_SET(ALT_QSPI_FLSHCMD_NUMADDRBYTES_E_ADDRBYTE3);
2354
2355    alt_write_word(ALT_QSPI_FLSHCMDADDR_ADDR, address);
2356
2357    return alt_qspi_stig_cmd_helper(reg, timeout);
2358}
2359
2360/////
2361
2362ALT_STATUS_CODE alt_qspi_device_wren(void) 
2363{
2364    // Write enable through STIG (not required, auto send by controller during write)
2365    return alt_qspi_stig_cmd(ALT_QSPI_STIG_OPCODE_WREN, 0, 10000);
2366}
2367
2368ALT_STATUS_CODE alt_qspi_device_wrdis(void) 
2369{
2370    // Write disable through STIG (not required, auto send by controller during write)
2371    return alt_qspi_stig_cmd(ALT_QSPI_STIG_OPCODE_WRDIS, 0, 10000);
2372}
2373
2374ALT_STATUS_CODE alt_qspi_device_rdid(uint32_t * rdid)
2375{
2376    // Read flash device ID through STIG
2377    return alt_qspi_stig_rd_cmd(ALT_QSPI_STIG_OPCODE_RDID, 0, 4, rdid, 10000);
2378}
2379
2380ALT_STATUS_CODE alt_qspi_discovery_parameter(uint32_t * param)
2381{
2382    // Read flash discovery parameters through STIG
2383
2384    return alt_qspi_stig_rd_cmd(ALT_QSPI_STIG_OPCODE_DISCVR_PARAM, 8, 8, param, 10000);
2385}
2386
2387ALT_STATUS_CODE alt_qspi_device_bank_select(uint32_t bank) 
2388{
2389    ALT_STATUS_CODE status = ALT_E_SUCCESS;
2390    dprintf("DEBUG[QSPI]: bank_select(): switching to bank 0x%" PRIu32 ".\n", bank);
2391
2392    if (status == ALT_E_SUCCESS)
2393    {
2394        status = alt_qspi_device_wren();
2395    }
2396
2397    if (status == ALT_E_SUCCESS)
2398    {
2399        status = alt_qspi_stig_wr_cmd(ALT_QSPI_STIG_OPCODE_WR_EXT_REG, 0, 1, &bank, 10000);
2400    }
2401
2402    if (status == ALT_E_SUCCESS)
2403    {
2404        status = alt_qspi_device_wrdis();
2405    }
2406
2407    return status;
2408}
2409
2410/////
2411
2412static bool alt_qspi_is_enabled(void)
2413{
2414    uint32_t cfg = alt_read_word(ALT_QSPI_CFG_ADDR);
2415
2416    if (cfg & ALT_QSPI_CFG_EN_SET_MSK)
2417    {
2418        return true;
2419    }
2420    else
2421    {
2422        return false;
2423    }
2424}
2425
2426ALT_STATUS_CODE alt_qspi_ecc_start(void * block, size_t size)
2427{
2428    if (size < (ALT_QSPI_PAGE_SIZE * 8))
2429    {
2430        return ALT_E_ERROR;
2431    }
2432
2433    if (alt_qspi_is_enabled() == false)
2434    {
2435        return ALT_E_ERROR;
2436    }
2437
2438    if (alt_qspi_is_idle() == false)
2439    {
2440        return ALT_E_ERROR;
2441    }
2442
2443    ALT_STATUS_CODE status = ALT_E_SUCCESS;
2444
2445    // 1. Configure SRAM Partition Register to 126 words for read, 2 words for write.
2446    // 2. Enable ECC on QSPI RAM
2447    // 3. Trigger an indirect read transfer that will fill up 126 words in FIFO by
2448    //    monitoring read FIFO fill level; Do not read out data through AHB.
2449    // 4. Start AHB read and start indirect write operation to write back to the same
2450    //    device location, this will fill up and initilaize the write partition RAM.
2451    // 5. To clear spurious interrupts, reset the QSPI controller.
2452
2453    // Save the previous partition size
2454
2455    uint32_t sram_orig = alt_qspi_sram_partition_get();
2456    dprintf("DEBUG[QSPI][ECC]: Save original SRAM as %" PRIu32 ".\n", sram_orig);
2457
2458    // Step 1
2459
2460    uint32_t sram_fill = (1 << ALT_QSPI_SRAMPART_ADDR_WIDTH) - 2;
2461    alt_qspi_sram_partition_set(sram_fill);
2462    dprintf("DEBUG[QSPI][ECC]: Set new SRAM as %" PRIu32 ".\n", sram_fill);
2463
2464    // Step 2
2465
2466    dprintf("DEBUG[QSPI][ECC]: Enable ECC in SysMgr.\n");
2467    alt_write_word(ALT_SYSMGR_ECC_QSPI_ADDR, ALT_SYSMGR_ECC_QSPI_EN_SET_MSK);
2468
2469    // Step 3
2470
2471    // Issue a read ~ 2x larger than the read partition. We will read out 1 page,
2472    // which will be used as the buffer to write back to QSPI. This way no data
2473    // actually changes thus no erase will be needed.
2474
2475    if (status == ALT_E_SUCCESS)
2476    {
2477        dprintf("DEBUG[QSPI][ECC]: Start indirect read PAGE * 8.\n");
2478        status = alt_qspi_indirect_read_start(0x0, ALT_QSPI_PAGE_SIZE * 8);
2479    }
2480
2481    // Read out 1 page for the write data
2482
2483    if (status == ALT_E_SUCCESS)
2484    {
2485        dprintf("DEBUG[QSPI][ECC]: Reading out 1 page ...\n");
2486
2487        uint32_t read_size = 0;
2488        char *   buffer    = block;
2489        while (read_size < ALT_QSPI_PAGE_SIZE)
2490        {
2491            uint32_t level = alt_qspi_indirect_read_fill_level();
2492            level = MIN(level, (ALT_QSPI_PAGE_SIZE - read_size) / sizeof(uint32_t));
2493
2494            uint32_t * data = (uint32_t *)(&buffer[read_size]);
2495            for (uint32_t i = 0; i < level; ++i)
2496            {
2497                *data = alt_read_word(ALT_QSPIDATA_ADDR);
2498                ++data;
2499            }
2500
2501            read_size += level * sizeof(uint32_t);
2502        }
2503
2504        if (read_size != ALT_QSPI_PAGE_SIZE)
2505        {
2506            status = ALT_E_ERROR;
2507        }
2508    }
2509
2510    // Wait for read FIFO to report it is up to the specified fill level.
2511
2512    if (status == ALT_E_SUCCESS)
2513    {
2514        dprintf("DEBUG[QSPI][ECC]: Waiting for read fill level ...\n");
2515
2516        uint32_t timeout = 10000;
2517
2518        while (alt_qspi_indirect_read_fill_level() < sram_fill)
2519        {
2520            if (--timeout == 0)
2521            {
2522                dprintf("DEBUG[QSPI][ECC]: Waiting for read fill timeout !!!\n");
2523                status = ALT_E_TMO;
2524                break;
2525            }
2526        }
2527    }
2528
2529    // Step 4
2530
2531    // Issue a write of 1 page of the same data from 0x0.
2532
2533    if (status == ALT_E_SUCCESS)
2534    {
2535        dprintf("DEBUG[QSPI][ECC]: Start indirect write PAGE.\n");
2536        status = alt_qspi_indirect_write_start(0x0, ALT_QSPI_PAGE_SIZE);
2537    }
2538
2539    if (status == ALT_E_SUCCESS)
2540    {
2541        dprintf("DEBUG[QSPI][ECC]: Writing in 1 page ...\n");
2542
2543        uint32_t write_size = 0;
2544        char *   buffer     = block;
2545
2546        while (write_size < ALT_QSPI_PAGE_SIZE)
2547        {
2548            uint32_t space = 2 - alt_qspi_indirect_write_fill_level();
2549            if (space == 0)
2550            {
2551                dprintf("DEBUG[QSPI][ECC]: Write FIFO filled at write_size = %" PRIu32 ".\n", write_size);
2552                // Space = 0; which means all 2 positions in the write FIFO is filled,
2553                // meaning it has been initialized with respect to ECC.
2554                break;
2555            }
2556
2557            space = MIN(space, (ALT_QSPI_PAGE_SIZE - write_size) / sizeof(uint32_t));
2558
2559            uint32_t * data = (uint32_t *)(&buffer[write_size]);
2560            for (uint32_t i = 0; i < space; ++i)
2561            {
2562                alt_write_word(ALT_QSPIDATA_ADDR, *data);
2563                ++data;
2564            }
2565
2566            write_size += space * sizeof(uint32_t);
2567        }
2568
2569        if (write_size != ALT_QSPI_PAGE_SIZE)
2570        {
2571            dprintf("DEBUG[QSPI][ECC]: Cancel indirect write.\n");
2572            status = alt_qspi_indirect_write_cancel();
2573        }
2574    }
2575
2576    if (status == ALT_E_SUCCESS)
2577    {
2578        dprintf("DEBUG[QSPI][ECC]: Finish indirect write.\n");
2579        status = alt_qspi_indirect_write_finish();
2580    }
2581
2582    // Cancel the indirect read as it has initialized the read FIFO partition.
2583
2584    if (status == ALT_E_SUCCESS)
2585    {
2586        dprintf("DEBUG[QSPI][ECC]: Cancel indirect read.\n");
2587        status = alt_qspi_indirect_read_cancel();
2588    }
2589
2590    if (status == ALT_E_SUCCESS)
2591    {
2592        dprintf("DEBUG[QSPI][ECC]: Finish indirect read.\n");
2593        status = alt_qspi_indirect_read_finish();
2594    }
2595
2596    // Step 5
2597
2598    if (status == ALT_E_SUCCESS)
2599    {
2600        dprintf("DEBUG[QSPI][ECC]: Clear any pending spurious QSPI ECC interrupts.\n");
2601
2602        alt_write_word(ALT_SYSMGR_ECC_QSPI_ADDR,
2603                         ALT_SYSMGR_ECC_QSPI_EN_SET_MSK
2604                       | ALT_SYSMGR_ECC_QSPI_SERR_SET_MSK
2605                       | ALT_SYSMGR_ECC_QSPI_DERR_SET_MSK);
2606    }
2607
2608    /////
2609
2610    // Restore original partition
2611
2612    if (status == ALT_E_SUCCESS)
2613    {
2614        dprintf("DEBUG[QSPI][ECC]: Restore original SRAM as %" PRIu32 ".\n", sram_orig);
2615        status = alt_qspi_sram_partition_set(sram_orig);
2616    }
2617
2618    return status;
2619}
Note: See TracBrowser for help on using the repository browser.