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