1 /***********************************************************************************************//**
2  * \file cy_serial_flash_qspi.c
3  *
4  * \brief
5  * Provides APIs for interacting with an external flash connected to the SPI or
6  * QSPI interface, uses SFDP to auto-discover memory properties if SFDP is
7  * enabled in the configuration.
8  *
9  ***************************************************************************************************
10  * \copyright
11  * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
12  * an affiliate of Cypress Semiconductor Corporation
13  *
14  * SPDX-License-Identifier: Apache-2.0
15  *
16  * Licensed under the Apache License, Version 2.0 (the "License");
17  * you may not use this file except in compliance with the License.
18  * You may obtain a copy of the License at
19  *
20  *     http://www.apache.org/licenses/LICENSE-2.0
21  *
22  * Unless required by applicable law or agreed to in writing, software
23  * distributed under the License is distributed on an "AS IS" BASIS,
24  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25  * See the License for the specific language governing permissions and
26  * limitations under the License.
27  **************************************************************************************************/
28 
29 #include <stdbool.h>
30 #include "cy_serial_flash_qspi.h"
31 #include "cyhal_qspi.h"
32 #include "cy_trigmux.h"
33 #include "cy_dma.h"
34 #include "cy_utils.h"
35 #if defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ)
36 #include "cyhal_irq_impl.h"
37 #endif /* defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ) */
38 
39 #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
40 #include <stdlib.h>
41 #include "cyabs_rtos.h"
42 #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
43 
44 #ifdef CY_IP_MXSMIF
45 
46 #if defined(__cplusplus)
47 extern "C" {
48 #endif
49 
50 
51 /** \cond INTERNAL */
52 
53 /** Timeout to apply while polling the memory for its ready status after quad
54  *  enable command has been sent out. Quad enable is a non-volatile write.
55  */
56 #define CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US      (5000lu) // in microseconds
57 
58 /** Number of loops to run while polling the SMIF for its busy status. */
59 #define SMIF_BUSY_CHECK_LOOP_COUNT                  (10lu)
60 
61 /** Timeout to apply per loop while polling the SMIF for its busy status. */
62 #define SMIF_BUSY_CHECK_TIMEOUT_MS                  (1lu) // in milliseconds
63 
64 // Number of memories supported by the driver
65 #define SMIF_MEM_DEVICES                            (1u)
66 
67 // SMIF slot from which the memory configuration is picked up - fixed to 0 as
68 // the driver supports only one device
69 #define MEM_SLOT                                    (0u)
70 
71 /* Maximum number of bytes that can be read by SMIF in one transfer */
72 #define SMIF_MAX_RX_COUNT                           (65536lu)
73 
74 #define DMA_YCOUNT_ONE_LOOP                         (1lu)
75 
76 #define MSB_SHIFT_EIGHT                             (0x08u)
77 #define LSB_MASK                                    (0xFFlu)
78 
79 /* Masks used for checking the flag bits */
80 #define FLAG_QSPI_HAL_INIT_DONE                     (0x01lu << 0)
81 #define FLAG_DMA_INIT_DONE                          (0x01lu << 1)
82 #define FLAG_READ_IN_PROGRESS                       (0x01lu << 2)
83 
84 #define IS_FLAG_SET(mask)                           (status_flags & (mask))
85 #define SET_FLAG(mask)                              (status_flags |= (mask))
86 #define CLEAR_FLAG(mask)                            (status_flags &= ~(mask))
87 
88 #if defined(CY_DEVICE_PSOC6ABLE2)
89 /* You cannot simply change these values. The trigger mux connect code in
90  * _init_dma() needs to be updated correspondingly.
91  */
92     #define RX_DMA_INSTANCE             DW1
93     #define RX_DMA_CHANNEL_NUM          (15lu)
94     #define RX_DMA_CH0_IRQn             (cpuss_interrupts_dw1_0_IRQn)
95     #define CY_SERIAL_FLASH_SMIF_IRQn   (smif_interrupt_IRQn)
96 #elif defined(CY_DEVICE_PSOC6A2M) || defined(CY_DEVICE_PSOC6A512K) || defined(CY_DEVICE_PSOC6A256K)
97 /* In these devices, only 1to1 triggers are available between SMIF and a
98  * specific combination of DW instances and channel numbers.
99  * i.e. TX trigger request from SMIF can connect only to DW1 CH22 and
100  * RX trigger request from SMIF can connect only to DW1 CH23.
101  */
102     #define RX_DMA_INSTANCE             DW1
103     #define RX_DMA_CHANNEL_NUM          (23lu)
104     #define RX_DMA_CH0_IRQn             (cpuss_interrupts_dw1_0_IRQn)
105     #define CY_SERIAL_FLASH_SMIF_IRQn   (smif_interrupt_IRQn)
106     #define DEVICE_GROUP_1TO1_TRIGGER
107     #define ONE_TO_ONE_TRIGGER_NAME     (TRIG_OUT_1TO1_3_SMIF_RX_TO_PDMA1_TR_IN23)
108 #elif defined(CY_DEVICE_CYW20829)
109     #define RX_DMA_INSTANCE             DW0
110     #define RX_DMA_CHANNEL_NUM          (0u)
111     #define RX_DMA_CH0_IRQn             (cpuss_interrupts_dw0_0_IRQn)
112     #define CY_SERIAL_FLASH_SMIF_IRQn   (smif_interrupt_normal_IRQn)
113 #elif defined(CY_DEVICE_TVIIBH4M) || defined(CY_DEVICE_TVIIBH8M)
114     #define RX_DMA_INSTANCE             DW1
115     #define RX_DMA_CHANNEL_NUM          (54u)
116     #define RX_DMA_CH0_IRQn             (cpuss_interrupts_dw1_0_IRQn)
117     #define CY_SERIAL_FLASH_SMIF_IRQn   (smif_0_interrupt_IRQn)
118     #define DEVICE_GROUP_1TO1_TRIGGER
119     #define ONE_TO_ONE_TRIGGER_NAME     (TRIG_OUT_1TO1_3_SMIF_RX_TO_PDMA1)
120 #else // if defined(CY_DEVICE_PSOC6ABLE2)
121     #define DMA_UNSUPPORTED
122 #endif // if defined(CY_DEVICE_PSOC6ABLE2)
123 
124 #define DMA_CHANNEL_PRIORITY            (3lu)
125 #define DMA_INTR_PRIORITY               ((uint8_t)((1u << __NVIC_PRIO_BITS) - 1u))
126 
127 /** \endcond */
128 
129 static cyhal_qspi_t qspi_obj;
130 static volatile uint32_t status_flags;
131 static cy_stc_smif_mem_config_t* qspi_mem_config[SMIF_MEM_DEVICES];
132 
133 static cy_stc_smif_block_config_t qspi_block_config =
134 {
135     // The number of SMIF memories defined.
136     .memCount     = SMIF_MEM_DEVICES,
137     // The pointer to the array of memory config structures of size memCount.
138     .memConfig    = (cy_stc_smif_mem_config_t**)qspi_mem_config,
139     // The version of the SMIF driver.
140     .majorVersion = CY_SMIF_DRV_VERSION_MAJOR,
141     // The version of the SMIF driver.
142     .minorVersion = CY_SMIF_DRV_VERSION_MINOR
143 };
144 
145 #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
146 static cy_mutex_t serial_flash_mutex;
147 #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
148 
149 #ifndef DMA_UNSUPPORTED
150 typedef struct
151 {
152     uint32_t addr;
153     size_t length;
154     uint8_t* buf;
155     cy_serial_flash_qspi_read_complete_callback_t callback;
156     void* callback_arg;
157 } read_txfr_info_t;
158 
159 static read_txfr_info_t read_txfr_info;
160 
161 /* DMA related variables */
162 static cy_stc_dma_descriptor_t dma_descr;
163 
164 /* Default DW descriptor config */
165 static cy_stc_dma_descriptor_config_t dma_descr_config =
166 {
167     .retrigger       = CY_DMA_RETRIG_4CYC,
168     .interruptType   = CY_DMA_DESCR,
169     .triggerOutType  = CY_DMA_DESCR_CHAIN,
170     .channelState    = CY_DMA_CHANNEL_ENABLED,
171     .triggerInType   = CY_DMA_DESCR,
172     .dataSize        = CY_DMA_BYTE,
173     .srcTransferSize = CY_DMA_TRANSFER_SIZE_WORD,
174     .dstTransferSize = CY_DMA_TRANSFER_SIZE_DATA,
175     .descriptorType  = CY_DMA_2D_TRANSFER,
176     .srcAddress      = 0,
177     .dstAddress      = 0,
178     .srcXincrement   = 0U,
179     .dstXincrement   = 1U,
180     .xCount          = 1UL,
181     .srcYincrement   = 0U,
182     .dstYincrement   = CY_DMA_LOOP_COUNT_MAX,
183     .yCount          = 1UL,
184     .nextDescriptor  = &dma_descr,
185 };
186 
187 /* Default DW channel config */
188 static cy_stc_dma_channel_config_t dma_channel_config =
189 {
190     .descriptor  = &dma_descr,
191     .preemptable = false,
192     .priority    = DMA_CHANNEL_PRIORITY,
193     .enable      = false,
194     .bufferable  = false,
195 };
196 
197 static const cyhal_resource_inst_t DW_obj =
198 {
199     .type        = CYHAL_RSC_DW,
200     .block_num   = ((uint32_t)RX_DMA_INSTANCE - DW0_BASE)/sizeof(DW_Type),
201     .channel_num = RX_DMA_CHANNEL_NUM
202 };
203 
204 static cy_rslt_t _init_dma(void);
205 static cy_rslt_t _deinit_dma(void);
206 static void _rx_dma_irq_handler(void);
207 static cy_en_smif_status_t _read_next_chunk(void);
208 #if !defined(CY_DEVICE_CYW20829)
209 static void _value_to_byte_array(uint32_t value, uint8_t* byte_array, uint32_t start_pos,
210                                  uint32_t size);
211 #endif /* #if !defined(CY_DEVICE_CYW20829) */
212 #endif /* #ifndef DMA_UNSUPPORTED */
213 
214 static inline cy_rslt_t _mutex_acquire(void);
215 static inline cy_rslt_t _mutex_release(void);
216 
217 #if defined(CY_DEVICE_CYW20829)
218 static cy_stc_smif_context_t SMIFContext;
219 #endif /* defined(CY_DEVICE_CYW20829) */
220 
221 //--------------------------------------------------------------------------------------------------
222 // cy_serial_flash_qspi_init
223 //
224 // The driver supports only one memory. When multiple memory configurations are generated by the
225 // SMIF configurator tool, provide only the configuration for memory that need to be supported by
226 // the driver.  Memory configuration can be changed by deinit followed by init with new
227 // configuration
228 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_init(const cy_stc_smif_mem_config_t * mem_config,cyhal_gpio_t io0,cyhal_gpio_t io1,cyhal_gpio_t io2,cyhal_gpio_t io3,cyhal_gpio_t io4,cyhal_gpio_t io5,cyhal_gpio_t io6,cyhal_gpio_t io7,cyhal_gpio_t sclk,cyhal_gpio_t ssel,uint32_t hz)229 cy_rslt_t cy_serial_flash_qspi_init(
230     const cy_stc_smif_mem_config_t* mem_config,
231     cyhal_gpio_t io0,
232     cyhal_gpio_t io1,
233     cyhal_gpio_t io2,
234     cyhal_gpio_t io3,
235     cyhal_gpio_t io4,
236     cyhal_gpio_t io5,
237     cyhal_gpio_t io6,
238     cyhal_gpio_t io7,
239     cyhal_gpio_t sclk,
240     cyhal_gpio_t ssel,
241     uint32_t hz)
242 {
243     cy_rslt_t result = CY_RSLT_SUCCESS;
244     cy_en_smif_status_t smif_status = CY_SMIF_SUCCESS;
245 
246     #if (CYHAL_API_VERSION >= 2)
247     // SMIF is already initialized for 20829 hence we can skip calling cyhal_qspi_init.
248     // initializing only the SMIF base address and the context variables for 20829.
249     #if defined(CY_DEVICE_CYW20829)
250     qspi_obj.base = SMIF0;
251     qspi_obj.context = SMIFContext;
252     #else /* defined(CY_DEVICE_CYW20829) */
253     cyhal_qspi_slave_pin_config_t memory_pin_set =
254     {
255         .io   = { io0, io1, io2, io3, io4, io5, io6, io7 },
256         .ssel = ssel
257     };
258     result = cyhal_qspi_init(&qspi_obj, sclk, &memory_pin_set, hz, 0, NULL);
259     #endif /* defined(CY_DEVICE_CYW20829) */
260 
261     #else /* HAL API version 1 */
262     result = cyhal_qspi_init(&qspi_obj, io0, io1, io2, io3, io4, io5, io6, io7, sclk, ssel, hz, 0);
263     #endif /* HAL API version 1 */
264 
265     qspi_mem_config[MEM_SLOT] = (cy_stc_smif_mem_config_t*)mem_config;
266 
267     if (CY_RSLT_SUCCESS == result)
268     {
269         SET_FLAG(FLAG_QSPI_HAL_INIT_DONE);
270 
271         // Perform SFDP detection and XIP register configuration depending on the memory
272         // configuration.
273         smif_status = Cy_SMIF_MemInit(qspi_obj.base, &qspi_block_config, &qspi_obj.context);
274         if (CY_SMIF_SUCCESS == smif_status)
275         {
276             // Enable Quad mode (1-1-4 or 1-4-4 modes) to use all the four I/Os during
277             // communication.
278 
279             if ((qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->readCmd->dataWidth ==
280                  CY_SMIF_WIDTH_QUAD) ||
281                 (qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programCmd->dataWidth ==
282                  CY_SMIF_WIDTH_QUAD))
283             {
284                 bool isQuadEnabled = false;
285                 smif_status =
286                     Cy_SMIF_MemIsQuadEnabled(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT],
287                                              &isQuadEnabled, &qspi_obj.context);
288                 if ((CY_SMIF_SUCCESS == smif_status) && !isQuadEnabled)
289                 {
290                     smif_status =
291                         Cy_SMIF_MemEnableQuadMode(qspi_obj.base,
292                                                   qspi_block_config.memConfig[MEM_SLOT],
293                                                   CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US,
294                                                   &qspi_obj.context);
295                 }
296             }
297             if (CY_SMIF_SUCCESS == smif_status)
298             {
299                 #ifndef DMA_UNSUPPORTED
300                 result = _init_dma();
301 
302                 if (CY_RSLT_SUCCESS == result)
303                 {
304                     SET_FLAG(FLAG_DMA_INIT_DONE);
305                 #endif /* #ifndef DMA_UNSUPPORTED */
306 
307                 #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
308                 /* Initialize the mutex */
309                 result = cy_rtos_init_mutex(&serial_flash_mutex);
310                 #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
311 
312                 #ifndef DMA_UNSUPPORTED
313             }
314                 #endif /* #ifndef DMA_UNSUPPORTED */
315             }
316         }
317     }
318 
319     if ((CY_RSLT_SUCCESS != result) || (CY_SMIF_SUCCESS != smif_status))
320     {
321         cy_serial_flash_qspi_deinit();
322 
323         if (CY_SMIF_SUCCESS != smif_status)
324         {
325             result = (cy_rslt_t)smif_status;
326         }
327     }
328 
329     return result;
330 }
331 
332 
333 //--------------------------------------------------------------------------------------------------
334 // cy_serial_flash_qspi_deinit
335 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_deinit(void)336 void cy_serial_flash_qspi_deinit(void)
337 {
338     cy_rslt_t result;
339 
340     if (IS_FLAG_SET(FLAG_QSPI_HAL_INIT_DONE))
341     {
342         /* For CYW20829, BOOTROM enables XIP by default and user is not expected to
343            disable memory while in XIP */
344         #if !defined(CY_DEVICE_CYW20829)
345         if (qspi_obj.base != NULL)
346         {
347             /* There is no harm in calling this even if Cy_SMIF_MemInit() did
348              * not succeed since anyway we own the QSPI object.
349              */
350             Cy_SMIF_MemDeInit(qspi_obj.base);
351         }
352 
353         cyhal_qspi_free(&qspi_obj);
354         #endif /* !defined(CY_DEVICE_CYW20829) */
355         CLEAR_FLAG(FLAG_QSPI_HAL_INIT_DONE);
356 
357         #ifndef DMA_UNSUPPORTED
358         if (IS_FLAG_SET(FLAG_DMA_INIT_DONE))
359         {
360             result = _deinit_dma();
361             CY_ASSERT(CY_RSLT_SUCCESS == result);
362 
363             CLEAR_FLAG(FLAG_DMA_INIT_DONE);
364         #endif /* #ifndef DMA_UNSUPPORTED */
365 
366         #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
367         result = cy_rtos_deinit_mutex(&serial_flash_mutex);
368         CY_ASSERT(CY_RSLT_SUCCESS == result);
369         #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
370 
371         #ifndef DMA_UNSUPPORTED
372     }
373         #endif /* #ifndef DMA_UNSUPPORTED */
374     }
375 
376     CY_UNUSED_PARAMETER(result); /* To avoid compiler warning in Release mode. */
377 }
378 
379 
380 //--------------------------------------------------------------------------------------------------
381 // cy_serial_flash_qspi_get_size
382 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_get_size(void)383 size_t cy_serial_flash_qspi_get_size(void)
384 {
385     return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->memSize;
386 }
387 
388 
389 //--------------------------------------------------------------------------------------------------
390 // cy_serial_flash_qspi_get_erase_size
391 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_get_erase_size(uint32_t addr)392 size_t cy_serial_flash_qspi_get_erase_size(uint32_t addr)
393 {
394     size_t                            erase_sector_size;
395     cy_stc_smif_hybrid_region_info_t* hybrid_info = NULL;
396 
397     cy_en_smif_status_t smif_status =
398         Cy_SMIF_MemLocateHybridRegion(qspi_block_config.memConfig[MEM_SLOT], &hybrid_info, addr);
399 
400     if (CY_SMIF_SUCCESS != smif_status)
401     {
402         erase_sector_size = (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->eraseSize;
403     }
404     else
405     {
406         erase_sector_size = (size_t)hybrid_info->eraseSize;
407     }
408 
409     return erase_sector_size;
410 }
411 
412 
413 //--------------------------------------------------------------------------------------------------
414 // cy_serial_flash_qspi_get_prog_size
415 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_get_prog_size(uint32_t addr)416 size_t cy_serial_flash_qspi_get_prog_size(uint32_t addr)
417 {
418     CY_UNUSED_PARAMETER(addr);
419     return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programSize;
420 }
421 
422 
423 //--------------------------------------------------------------------------------------------------
424 // cy_serial_flash_qspi_read
425 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_read(uint32_t addr,size_t length,uint8_t * buf)426 cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t* buf)
427 {
428     cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS;
429 
430     cy_rslt_t result = _mutex_acquire();
431 
432     if (CY_RSLT_SUCCESS == result)
433     {
434         // Cy_SMIF_MemRead() returns error if (addr + length) > total flash size.
435         result = (cy_rslt_t)Cy_SMIF_MemRead(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT],
436                                             addr,
437                                             buf, length, &qspi_obj.context);
438         result_mutex_rel = _mutex_release();
439     }
440 
441     /* Give priority to the status of SMIF operation when both SMIF operation
442      * and mutex release fail.
443      */
444     return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result);
445 }
446 
447 
448 //--------------------------------------------------------------------------------------------------
449 // cy_serial_flash_qspi_abort_read
450 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_abort_read(void)451 cy_rslt_t cy_serial_flash_qspi_abort_read(void)
452 {
453     #ifndef DMA_UNSUPPORTED
454     cy_rslt_t result;
455 
456     /* Wait until SMIF finishes any pending transfer. */
457     for (uint32_t loop = 0; loop < SMIF_BUSY_CHECK_LOOP_COUNT; loop++)
458     {
459         if (!Cy_SMIF_BusyCheck(qspi_obj.base))
460         {
461             break;
462         }
463 
464         cyhal_system_delay_ms(SMIF_BUSY_CHECK_TIMEOUT_MS);
465     }
466 
467     if (Cy_SMIF_BusyCheck(qspi_obj.base))
468     {
469         SET_FLAG(FLAG_READ_IN_PROGRESS);
470         result = CY_RSLT_SERIAL_FLASH_ERR_QSPI_BUSY;
471     }
472     else
473     {
474         Cy_DMA_Channel_Disable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
475         result = CY_RSLT_SUCCESS;
476         CLEAR_FLAG(FLAG_READ_IN_PROGRESS);
477     }
478 
479     return result;
480     #else // ifndef DMA_UNSUPPORTED
481     return CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED;
482     #endif /* #ifndef DMA_UNSUPPORTED */
483 }
484 
485 
486 //--------------------------------------------------------------------------------------------------
487 // cy_serial_flash_qspi_read_async
488 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_read_async(uint32_t addr,size_t length,uint8_t * buf,cy_serial_flash_qspi_read_complete_callback_t callback,void * callback_arg)489 cy_rslt_t cy_serial_flash_qspi_read_async(uint32_t addr, size_t length, uint8_t* buf,
490                                           cy_serial_flash_qspi_read_complete_callback_t callback,
491                                           void* callback_arg)
492 {
493     #ifndef DMA_UNSUPPORTED
494     cy_rslt_t result = CY_RSLT_SERIAL_FLASH_ERR_BAD_PARAM;
495     cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS;
496 
497     CY_ASSERT(NULL != buf);
498 
499     if (IS_FLAG_SET(FLAG_READ_IN_PROGRESS))
500     {
501         result = CY_RSLT_SERIAL_FLASH_ERR_READ_BUSY; /* Previous read request is not yet complete.
502                                                       */
503     }
504     else if ((addr + length) <= cy_serial_flash_qspi_get_size())
505     {
506         result = _mutex_acquire();
507 
508         if (CY_RSLT_SUCCESS == result)
509         {
510             read_txfr_info.addr = addr;
511             read_txfr_info.length = length;
512             read_txfr_info.buf = buf;
513             read_txfr_info.callback = callback;
514             read_txfr_info.callback_arg = callback_arg;
515 
516             /* Enable the DMA channel */
517             Cy_DMA_Channel_Enable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
518 
519             SET_FLAG(FLAG_READ_IN_PROGRESS);
520             result = (cy_rslt_t)_read_next_chunk();  /* Start the read transfer */
521 
522             if (CY_RSLT_SUCCESS != result)
523             {
524                 CLEAR_FLAG(FLAG_READ_IN_PROGRESS);
525             }
526 
527             result_mutex_rel = _mutex_release();
528         }
529     }
530 
531     /* Give priority to the status of SMIF operation when both SMIF operation
532      * and mutex release fail.
533      */
534     return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result);
535     #else // ifndef DMA_UNSUPPORTED
536     CY_UNUSED_PARAMETER(addr);
537     CY_UNUSED_PARAMETER(length);
538     CY_UNUSED_PARAMETER(buf);
539     CY_UNUSED_PARAMETER(callback);
540     CY_UNUSED_PARAMETER(callback_arg);
541 
542     return CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED;
543     #endif /* #ifndef DMA_UNSUPPORTED */
544 }
545 
546 
547 //--------------------------------------------------------------------------------------------------
548 // cy_serial_flash_qspi_write
549 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_write(uint32_t addr,size_t length,const uint8_t * buf)550 cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t* buf)
551 {
552     cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS;
553 
554     cy_rslt_t result = _mutex_acquire();
555 
556     if (CY_RSLT_SUCCESS == result)
557     {
558         // Cy_SMIF_MemWrite() returns error if (addr + length) > total flash size.
559         result = (cy_rslt_t)Cy_SMIF_MemWrite(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT],
560                                              addr,
561                                              (uint8_t*)buf, length, &qspi_obj.context);
562         result_mutex_rel = _mutex_release();
563     }
564 
565     /* Give priority to the status of SMIF operation when both SMIF operation
566      * and mutex release fail.
567      */
568     return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result);
569 }
570 
571 
572 //--------------------------------------------------------------------------------------------------
573 // cy_serial_flash_qspi_erase
574 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_erase(uint32_t addr,size_t length)575 cy_rslt_t cy_serial_flash_qspi_erase(uint32_t addr, size_t length)
576 {
577     cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS;
578 
579     cy_rslt_t result = _mutex_acquire();
580 
581     if (CY_RSLT_SUCCESS == result)
582     {
583         // If the erase is for the entire chip, use chip erase command
584         if ((addr == 0u) && (length == cy_serial_flash_qspi_get_size()))
585         {
586             result =
587                 (cy_rslt_t)Cy_SMIF_MemEraseChip(qspi_obj.base,
588                                                 qspi_block_config.memConfig[MEM_SLOT],
589                                                 &qspi_obj.context);
590         }
591         else
592         {
593             // Cy_SMIF_MemEraseSector() returns error if (addr + length) > total flash size or if
594             // addr is not aligned to erase sector size or if (addr + length) is not aligned to
595             // erase sector size.
596             result =
597                 (cy_rslt_t)Cy_SMIF_MemEraseSector(qspi_obj.base,
598                                                   qspi_block_config.memConfig[MEM_SLOT],
599                                                   addr, length, &qspi_obj.context);
600         }
601 
602         result_mutex_rel = _mutex_release();
603     }
604 
605     /* Give priority to the status of SMIF operation when both SMIF operation
606      * and mutex release fail.
607      */
608     return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result);
609 }
610 
611 
612 //--------------------------------------------------------------------------------------------------
613 // cy_serial_flash_qspi_enable_xip
614 //
615 // This function enables or disables XIP on the MCU, does not send any command
616 // to the serial flash. XIP register configuration is already done as part of
617 // cy_serial_flash_qspi_init() if MMIO mode is enabled in the QSPI
618 // Configurator.
619 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_enable_xip(bool enable)620 cy_rslt_t cy_serial_flash_qspi_enable_xip(bool enable)
621 {
622     if (enable)
623     {
624         Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_MEMORY);
625     }
626     else
627     {
628         Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_NORMAL);
629     }
630 
631     return CY_RSLT_SUCCESS;
632 }
633 
634 
635 //--------------------------------------------------------------------------------------------------
636 // cy_serial_flash_qspi_set_interrupt_priority
637 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_set_interrupt_priority(uint8_t priority)638 void cy_serial_flash_qspi_set_interrupt_priority(uint8_t priority)
639 {
640     #if defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ)
641     _cyhal_irq_set_priority(CY_SERIAL_FLASH_SMIF_IRQn, priority);
642     #else
643     NVIC_SetPriority(CY_SERIAL_FLASH_SMIF_IRQn, priority);
644     #endif /* defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ) or other */
645 }
646 
647 
648 //--------------------------------------------------------------------------------------------------
649 // cy_serial_flash_qspi_set_interrupt_priority
650 //--------------------------------------------------------------------------------------------------
cy_serial_flash_qspi_set_dma_interrupt_priority(uint8_t priority)651 void cy_serial_flash_qspi_set_dma_interrupt_priority(uint8_t priority)
652 {
653     #ifndef DMA_UNSUPPORTED
654     #if defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ)
655     _cyhal_irq_set_priority((_cyhal_system_irq_t)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM), priority);
656     #else
657     NVIC_SetPriority((IRQn_Type)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM), priority);
658     #endif /* #if defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ) or other */
659     #else
660     CY_UNUSED_PARAMETER(priority);
661     #endif /* #ifndef DMA_UNSUPPORTED */
662 }
663 
664 
665 #ifndef DMA_UNSUPPORTED
666 //--------------------------------------------------------------------------------------------------
667 // _read_next_chunk
668 //--------------------------------------------------------------------------------------------------
_read_next_chunk(void)669 static cy_en_smif_status_t _read_next_chunk(void)
670 {
671     cy_en_smif_status_t smif_status = CY_SMIF_SUCCESS;
672     uint32_t chunk;
673     #if !defined(CY_DEVICE_CYW20829)
674     uint8_t addr_array[CY_SMIF_FOUR_BYTES_ADDR] = { 0U };
675     #endif /* !defined(CY_DEVICE_CYW20829) */
676 
677     if (read_txfr_info.length > 0UL)
678     {
679         /* SMIF can read only up to 65536 bytes in one go. Split the larger read into multiple
680            chunks */
681         chunk =
682             (read_txfr_info.length >
683              SMIF_MAX_RX_COUNT) ? (SMIF_MAX_RX_COUNT) : read_txfr_info.length;
684 
685         /* In 2D transfer, (X_count x Y_count) should be a multiple of CY_DMA_LOOP_COUNT_MAX (256).
686          */
687         if (chunk > CY_DMA_LOOP_COUNT_MAX)
688         {
689             /* Make chunk divisible by CY_DMA_LOOP_COUNT_MAX (256) by masking out the LS bits */
690             chunk &= ~(CY_DMA_LOOP_COUNT_MAX - 1);
691 
692             dma_descr_config.yCount = chunk/CY_DMA_LOOP_COUNT_MAX;
693             dma_descr_config.xCount = CY_DMA_LOOP_COUNT_MAX;
694         }
695         else
696         {
697             dma_descr_config.yCount = DMA_YCOUNT_ONE_LOOP;
698             dma_descr_config.xCount = chunk;
699         }
700 
701         dma_descr_config.dstAddress = (void*)read_txfr_info.buf;
702         #if defined(CY_DEVICE_CYW20829)
703         dma_descr_config.dataSize = CY_DMA_BYTE;
704         dma_descr_config.srcTransferSize = CY_DMA_TRANSFER_SIZE_DATA,
705         dma_descr_config.srcXincrement = 1;
706         dma_descr_config.srcAddress =
707             (void*)(qspi_block_config.memConfig[MEM_SLOT]->baseAddress + read_txfr_info.addr);
708         #endif /* defined(CY_DEVICE_CYW20829) */
709         Cy_DMA_Descriptor_Init(&dma_descr, &dma_descr_config);
710 
711         #if defined(CY_DEVICE_CYW20829)
712         Cy_TrigMux_SwTrigger(TRIG_OUT_MUX_0_PDMA0_TR_IN0, CY_TRIGGER_TWO_CYCLES);
713         #else /* defined(CY_DEVICE_CYW20829) */
714         /* Pass NULL for buffer (and callback) so that the function does not
715          * set up FIFO interrupt. We don't need FIFO interrupt to be setup
716          * since we will be using DMA.
717          */
718         _value_to_byte_array(read_txfr_info.addr, &addr_array[0], 0UL,
719                              qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->numOfAddrBytes);
720         smif_status = Cy_SMIF_MemCmdRead(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT],
721                                          addr_array, NULL, chunk, NULL, &qspi_obj.context);
722 
723         if (CY_SMIF_SUCCESS == smif_status)
724         #endif /* defined(CY_DEVICE_CYW20829) */
725         {
726             /* Recalculate the next rxBuffer offset */
727             read_txfr_info.length -= chunk;
728             read_txfr_info.addr += chunk;
729             read_txfr_info.buf += chunk;
730         }
731     }
732 
733     return smif_status;
734 }
735 
736 
737 //--------------------------------------------------------------------------------------------------
738 // _init_dma
739 //--------------------------------------------------------------------------------------------------
_init_dma(void)740 static cy_rslt_t _init_dma(void)
741 {
742     cy_rslt_t result;
743 
744     /* Set the source address of the descriptor */
745     dma_descr_config.srcAddress = (void*)&SMIF_RX_DATA_FIFO_RD1(qspi_obj.base);
746 
747     /* Configure the RX DMA */
748     result =
749         (cy_rslt_t)Cy_DMA_Channel_Init(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM, &dma_channel_config);
750 
751     if (CY_RSLT_SUCCESS == result)
752     {
753         Cy_DMA_Channel_SetInterruptMask(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM, CY_DMA_INTR_MASK);
754         Cy_DMA_Enable(RX_DMA_INSTANCE);
755 
756         #if defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ)
757         _cyhal_irq_register((_cyhal_system_irq_t)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM),
758                             DMA_INTR_PRIORITY,
759                             _rx_dma_irq_handler);
760         _cyhal_irq_enable((_cyhal_system_irq_t)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM));
761         #else
762         /* Configure interrupt for RX DMA */
763         cy_stc_sysint_t dma_intr_config =
764             { .intrSrc        = (IRQn_Type)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM),
765               .intrPriority   = DMA_INTR_PRIORITY };
766         result = (cy_rslt_t)Cy_SysInt_Init(&dma_intr_config, _rx_dma_irq_handler);
767         if (CY_RSLT_SUCCESS == result)
768         #endif /* defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ) or other */
769         {
770             /* Configure the trigger mux */
771             #if defined(DEVICE_GROUP_1TO1_TRIGGER)
772             result = (cy_rslt_t)Cy_TrigMux_Select(ONE_TO_ONE_TRIGGER_NAME, false,
773                                                   TRIGGER_TYPE_LEVEL);
774             #else //defined(DEVICE_GROUP_1TO1_TRIGGER)
775             #if !defined(CY_DEVICE_CYW20829)
776 
777             result = (cy_rslt_t)Cy_TrigMux_Connect(TRIG13_IN_SMIF_TR_RX_REQ,
778                                                    TRIG13_OUT_TR_GROUP0_INPUT42, false,
779                                                    TRIGGER_TYPE_LEVEL);
780 
781             if (CY_RSLT_SUCCESS == result)
782             {
783                 result = (cy_rslt_t)Cy_TrigMux_Connect(TRIG1_IN_TR_GROUP13_OUTPUT15,
784                                                        TRIG1_OUT_CPUSS_DW1_TR_IN15, false,
785                                                        TRIGGER_TYPE_LEVEL);
786             }
787             #endif /*defined(CY_DEVICE_CYW20829)*/
788             #endif /* #if defined(DEVICE_GROUP_1TO1_TRIGGER) */
789         }
790     }
791 
792     if (CY_RSLT_SUCCESS == result)
793     {
794         /* Reserve the DW instance so that HAL will not be able to use it later. */
795         result = cyhal_hwmgr_reserve(&DW_obj);
796     }
797 
798     return result;
799 }
800 
801 
802 //--------------------------------------------------------------------------------------------------
803 // _deinit_dma
804 //--------------------------------------------------------------------------------------------------
_deinit_dma(void)805 static cy_rslt_t _deinit_dma(void)
806 {
807     cy_rslt_t result = CY_RSLT_SUCCESS;
808 
809     #if defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ)
810     _cyhal_irq_disable((_cyhal_system_irq_t)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM));
811     #else
812     NVIC_DisableIRQ((IRQn_Type)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM));
813     #endif /* defined(_CYHAL_DRIVER_AVAILABLE_IRQ) && (_CYHAL_DRIVER_AVAILABLE_IRQ) */
814 
815     /* Disable only the channel, not the DW instance as it may be used by other
816      * part of the application.
817      */
818     Cy_DMA_Channel_Disable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
819 
820     /* Free the DMA resource so that HAL can use it now */
821     cyhal_hwmgr_free(&DW_obj);
822 
823     #if defined(DEVICE_GROUP_1TO1_TRIGGER)
824     result = (cy_rslt_t)Cy_TrigMux_Deselect(ONE_TO_ONE_TRIGGER_NAME);
825     #else
826     /* No PDL function is available for handling deinit for non-1to1 trigger muxes. */
827     #endif /* #if defined(DEVICE_GROUP_1TO1_TRIGGER) */
828 
829     return result;
830 }
831 
832 
833 //--------------------------------------------------------------------------------------------------
834 // _rx_dma_irq_handler
835 //--------------------------------------------------------------------------------------------------
_rx_dma_irq_handler(void)836 static void _rx_dma_irq_handler(void)
837 {
838     cy_en_smif_status_t smif_status = CY_SMIF_SUCCESS;
839     bool terminate_read_txfr = true;
840     cy_en_dma_intr_cause_t cause = Cy_DMA_Channel_GetStatus(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
841 
842     Cy_DMA_Channel_ClearInterrupt(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
843 
844     if (CY_DMA_INTR_CAUSE_COMPLETION == cause)
845     {
846         if (read_txfr_info.length > 0UL)
847         {
848             smif_status = _read_next_chunk();
849 
850             if (CY_SMIF_SUCCESS == smif_status)
851             {
852                 terminate_read_txfr = false;
853             }
854         }
855     }
856     else
857     {
858         smif_status = (cy_en_smif_status_t)CY_RSLT_SERIAL_FLASH_ERR_DMA;
859     }
860 
861     if (terminate_read_txfr)
862     {
863         Cy_DMA_Channel_Disable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
864         CLEAR_FLAG(FLAG_READ_IN_PROGRESS);
865 
866         /* Execute the callback */
867         if (NULL != read_txfr_info.callback)
868         {
869             read_txfr_info.callback((cy_rslt_t)smif_status, read_txfr_info.callback_arg);
870         }
871     }
872 }
873 
874 
875 #if !defined(CY_DEVICE_CYW20829)
876 /*******************************************************************************
877 * Function Name: _value_to_byte_array
878 ****************************************************************************//**
879 *
880 * Unpacks the specified number of bytes from a 32-bit value into the given byte
881 * array.
882 *
883 * \param value
884 * The 32-bit (4-byte) value to unpack.
885 *
886 * \param byte_array
887 * The byte array to fill.
888 *
889 * \param start_pos
890 * The start position of the byte array to begin filling from.
891 *
892 * \param size
893 * The number of bytes to unpack.
894 *
895 *******************************************************************************/
_value_to_byte_array(uint32_t value,uint8_t * byte_array,uint32_t start_pos,uint32_t size)896 static void _value_to_byte_array(uint32_t value, uint8_t* byte_array, uint32_t start_pos,
897                                  uint32_t size)
898 {
899     CY_ASSERT((0lu < size) && (CY_SMIF_FOUR_BYTES_ADDR >= size));
900     CY_ASSERT(NULL != byte_array);
901 
902     do
903     {
904         size--;
905         byte_array[size + start_pos] = (uint8_t)(value & LSB_MASK);
906         value >>= MSB_SHIFT_EIGHT; /* Shift to get the next byte */
907     } while (size > 0U);
908 }
909 
910 
911 #endif /* #if !defined(CY_DEVICE_CYW20829)*/
912 
913 #endif /* #ifndef DMA_UNSUPPORTED */
914 
915 //--------------------------------------------------------------------------------------------------
916 // _mutex_acquire
917 //--------------------------------------------------------------------------------------------------
_mutex_acquire(void)918 static inline cy_rslt_t _mutex_acquire(void)
919 {
920     #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
921     return cy_rtos_get_mutex(&serial_flash_mutex, CY_RTOS_NEVER_TIMEOUT);
922     #else
923     return CY_RSLT_SUCCESS;
924     #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
925 }
926 
927 
928 //--------------------------------------------------------------------------------------------------
929 // _mutex_release
930 //--------------------------------------------------------------------------------------------------
_mutex_release(void)931 static inline cy_rslt_t _mutex_release(void)
932 {
933     #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
934     return cy_rtos_set_mutex(&serial_flash_mutex);
935     #else
936     return CY_RSLT_SUCCESS;
937     #endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
938 }
939 
940 
941 #if defined(__cplusplus)
942 }
943 #endif
944 
945 #endif // CY_IP_MXSMIF
946