1 /***************************************************************************//**
2 * \file cyhal_qspi.c
3 *
4 * Description:
5 * Provides a high level interface for interacting with the Infineon QSPI (SMIF).
6 * This is a wrapper around the lower level PDL API.
7 *
8 ********************************************************************************
9 * \copyright
10 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
11 * an affiliate of Cypress Semiconductor Corporation
12 *
13 * SPDX-License-Identifier: Apache-2.0
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 *     http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 *******************************************************************************/
27 
28 /**
29  * \addtogroup group_hal_impl_qspi QSPI (Quad Serial Peripheral Interface)
30  * \ingroup group_hal_impl
31  * \{
32  * \section section_hal_impl_qspi_init_cfg Configurator-generated features limitations
33  * List of SMIF personality items, which are currently not supported in QSPI HAL driver on CAT1A/CAT1B devices:
34  *  - XIP (eXecute In Place) mode
35  *  - Memory Mode Alignment Error interrupt
36  *  - RX Data FIFO Underflow interrupt
37  *  - TX Command FIFO Overflow
38  *  - TX Data FIFO Overflow interrupt
39  *  - RX FIFO Level Trigger interrupt
40  *  - TX FIFO Level Trigger interrupt
41  *  - RX DMA Trigger
42  *  - TX DMA Trigger
43  * Note: For CAT1D devices, the QSPI SCLK connection is provided with a dedicated pin so NC should be passed for the SCLK pin when calling cyhal_qspi_init.
44  *
45  * \section section_hal_impl_qspi_init_clock_20829 20829 device clock limitations
46  * Due to specifics of 20829 device clock tree, where multiple peripheral devices are clocked by same HF1, as
47  * QSPI HW Block, QSPI HAL driver is not allowed to manipulate frequency by itself. In this case user should allocate
48  * and configure their own HF1 clock and pass it as `cyhal_clock_t *clk` parameter into cyhal_qspi_init function.
49  *
50  * \section section_hal_impl_clock_freq Interface clock frequency
51  * Starting MXSMIF HW block version 2 (checked with `CY_IP_MXSMIF_VERSION` define), QSPI interface clock frequency is
52  * twice lower than configured source HF clock, so if QSPI source HF clock is configured, for instance, for 50 MHz, connected
53  * memory will be accessed on 25 MHz clock. Interface clock frequency of MXSMIF block with version 1 corresponds
54  * to frequency of source HF clock.
55  *
56  * \} group_hal_impl_qspi
57  */
58 
59 #include <string.h>
60 #include <math.h>
61 #include <stdlib.h>
62 #include "cy_smif.h"
63 #include "cyhal_utils.h"
64 #include "cyhal_irq_impl.h"
65 #include "cyhal_qspi.h"
66 #include "cyhal_hwmgr.h"
67 #include "cyhal_gpio.h"
68 #include "cyhal_interconnect.h"
69 #include "cyhal_system_impl.h"
70 #if CYHAL_DRIVER_AVAILABLE_SYSPM
71 #include "cyhal_syspm.h"
72 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
73 #include "cyhal_clock.h"
74 
75 #if (CYHAL_DRIVER_AVAILABLE_QSPI)
76 
77 #if defined(__cplusplus)
78 extern "C" {
79 #endif /* __cplusplus */
80 
81 /*******************************************************************************
82 *       Internal
83 *******************************************************************************/
84 /* in microseconds, timeout for all blocking functions */
85 #define _CYHAL_QSPI_TIMEOUT_10_MS (10000UL)
86 
87 #define _CYHAL_QSPI_MAX_DATA_PINS 8
88 
89 #define _CYHAL_QSPI_MAX_RX_COUNT (65536UL)
90 #define _CYHAL_QSPI_DESELECT_DELAY (7UL)
91 
92 #if (defined(SMIF_CHIP_TOP_DATA8_PRESENT) && (SMIF_CHIP_TOP_DATA8_PRESENT))   || \
93     (defined(SMIF0_CHIP_TOP_DATA8_PRESENT) && (SMIF0_CHIP_TOP_DATA8_PRESENT))
94     #define _CYHAL_QSPI_DATA8_PRESENT   1
95 #else
96     #define _CYHAL_QSPI_DATA8_PRESENT   0
97 #endif
98 #if (SMIF_CHIP_TOP_SPI_SEL_NR > 1)
99     #define _CYHAL_QSPI_SEL1   1
100 #else
101     #define _CYHAL_QSPI_SEL1   0
102 #endif
103 #if (SMIF_CHIP_TOP_SPI_SEL_NR > 2)
104     #define _CYHAL_QSPI_SEL2   1
105 #else
106     #define _CYHAL_QSPI_SEL2   0
107 #endif
108 #if (SMIF_CHIP_TOP_SPI_SEL_NR > 3)
109     #define _CYHAL_QSPI_SEL3   1
110 #else
111     #define _CYHAL_QSPI_SEL3   0
112 #endif
113 
114 static cyhal_qspi_t *_cyhal_qspi_config_structs[CY_IP_MXSMIF_INSTANCES];
115 
116 /* List of available QSPI instances */
117 
118 #if (CY_IP_MXSMIF_VERSION >= 4)
119 static SMIF_Type * const _cyhal_qspi_base_addresses[SMIF_SMIF_NR] =
120 {
121 #ifdef SMIF0_CORE0
122     SMIF0_CORE0,
123 #endif /* ifdef SMIF0_CORE0   */
124 #ifdef SMIF0_CORE1
125     SMIF0_CORE1,
126 #endif /* ifdef SMIF0_CORE1 */
127 };
128 #else
129 static SMIF_Type *const _cyhal_qspi_base_addresses[CY_IP_MXSMIF_INSTANCES] =
130 {
131 #ifdef SMIF0
132     SMIF0,
133 #endif /* ifdef SMIF0 */
134 };
135 #endif
136 
137 /* List of available QSPI interrupt sources */
138 #if (CY_IP_MXSMIF_VERSION >= 4)
139 static const _cyhal_system_irq_t _cyhal_qspi_irq_n[SMIF_SMIF_NR] =
140 {
141 #ifdef SMIF0_CORE0
142     smif_0_smif0_interrupt_IRQn,
143 #endif /* ifdef SMIF0_CORE0 */
144 
145 #ifdef SMIF0_CORE1
146     smif_0_smif1_interrupt_IRQn,
147 #endif /* ifdef SMIF0_CORE1 */
148 };
149 #else
150 static const _cyhal_system_irq_t _cyhal_qspi_irq_n[CY_IP_MXSMIF_INSTANCES] =
151 {
152 #ifdef SMIF0
153 #if (CY_IP_MXSMIF_VERSION >= 3)
154     smif_interrupt_normal_IRQn,
155 #elif (CY_IP_MXSMIF_VERSION == 2)
156     smif_0_interrupt_IRQn,
157 #else
158     smif_interrupt_IRQn,
159 #endif
160 #endif /* ifdef SMIF0 */
161 };
162 #endif
163 
_cyhal_qspi_get_block_from_irqn(_cyhal_system_irq_t irqn)164 static inline uint8_t _cyhal_qspi_get_block_from_irqn(_cyhal_system_irq_t irqn)
165 {
166     for(uint8_t i = 0; i < (sizeof(_cyhal_qspi_irq_n)/sizeof(_cyhal_qspi_irq_n[0])) ;i++ )
167     {
168         if (_cyhal_qspi_irq_n[i] == irqn)
169         {
170             return i;
171         }
172     }
173     CY_ASSERT(false); // Should never be called with a non-SMIF IRQn
174     return 0;
175 }
176 
_cyhal_qspi_get_irq_obj(void)177 static cyhal_qspi_t *_cyhal_qspi_get_irq_obj(void)
178 {
179     _cyhal_system_irq_t irqn = _cyhal_irq_get_active();
180     uint8_t block = _cyhal_qspi_get_block_from_irqn(irqn);
181     return _cyhal_qspi_config_structs[block];
182 }
183 
184 #if CYHAL_DRIVER_AVAILABLE_SYSPM
_cyhal_qspi_set_pins_frozen(cyhal_qspi_t * obj,bool freeze)185 static void _cyhal_qspi_set_pins_frozen(cyhal_qspi_t* obj, bool freeze)
186 {
187     GPIO_PRT_Type* port;
188     uint8_t pin;
189     cyhal_gpio_t gpio;
190     for(size_t i = 0; i < _CYHAL_QSPI_MAX_DATA_PINS; ++i)
191     {
192         gpio = obj->pin_io[i];
193         if(NC != gpio)
194         {
195             port = CYHAL_GET_PORTADDR(gpio);
196             pin = (uint8_t)CYHAL_GET_PIN(gpio);
197             if(freeze)
198             {
199                 obj->saved_io_hsiom[i] = Cy_GPIO_GetHSIOM(port, pin);
200                 Cy_GPIO_Clr(port, pin);
201                 Cy_GPIO_SetHSIOM(port, pin, HSIOM_SEL_GPIO);
202             }
203             else
204             {
205                 Cy_GPIO_SetHSIOM(port, pin, obj->saved_io_hsiom[i]);
206             }
207         }
208     }
209 
210     gpio = obj->pin_sclk;
211     if(NC != gpio)
212     {
213         port = CYHAL_GET_PORTADDR(gpio);
214         pin = (uint8_t)CYHAL_GET_PIN(gpio);
215         if(freeze)
216         {
217             obj->saved_sclk_hsiom = Cy_GPIO_GetHSIOM(port, pin);
218             Cy_GPIO_Clr(port, pin);
219             Cy_GPIO_SetHSIOM(port, pin, HSIOM_SEL_GPIO);
220         }
221         else
222         {
223             Cy_GPIO_SetHSIOM(port, pin, obj->saved_sclk_hsiom);
224         }
225     }
226 
227     for(size_t i = 0; i < SMIF_CHIP_TOP_SPI_SEL_NR; ++i)
228     {
229         gpio = obj->pin_ssel[i];
230         if(NC != gpio)
231         {
232             port = CYHAL_GET_PORTADDR(gpio);
233             pin = (uint8_t)CYHAL_GET_PIN(gpio);
234             if(freeze)
235             {
236                 obj->saved_ssel_hsiom[i] = Cy_GPIO_GetHSIOM(port, pin);
237                 Cy_GPIO_Set(port, pin); // The SMIF IP requires SSEL to be active low
238                 Cy_GPIO_SetHSIOM(port, pin, HSIOM_SEL_GPIO);
239             }
240             else
241             {
242                 Cy_GPIO_SetHSIOM(port, pin, obj->saved_ssel_hsiom[i]);
243             }
244         }
245     }
246 }
247 
_cyhal_qspi_pm_callback(cyhal_syspm_callback_state_t state,cyhal_syspm_callback_mode_t mode,void * callback_arg)248 static bool _cyhal_qspi_pm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void* callback_arg)
249 {
250     CY_UNUSED_PARAMETER(state);
251     cyhal_qspi_t *obj = (cyhal_qspi_t *)callback_arg;
252     bool allow = true;
253     switch(mode)
254     {
255         case CYHAL_SYSPM_CHECK_READY:
256             allow &= obj->context.txBufferCounter == 0;
257             allow &= obj->context.rxBufferCounter == 0;
258             allow &= Cy_SMIF_GetRxFifoStatus(obj->base) == 0;
259             allow &= Cy_SMIF_GetTxFifoStatus(obj->base) == 0;
260             if (allow)
261             {
262                 obj->pm_transition_pending = true;
263             }
264             break;
265         case CYHAL_SYSPM_BEFORE_TRANSITION:
266             _cyhal_qspi_set_pins_frozen(obj, true);
267             break;
268         case CYHAL_SYSPM_AFTER_TRANSITION:
269             _cyhal_qspi_set_pins_frozen(obj, false);
270             obj->pm_transition_pending = false;
271             break;
272         case CYHAL_SYSPM_CHECK_FAIL:
273             obj->pm_transition_pending = false;
274             break;
275         default:
276             CY_ASSERT(false);
277             break;
278     }
279     return allow;
280 }
281 #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
282 
283 /*******************************************************************************
284 *       Dispatcher Interrupt Service Routine
285 *******************************************************************************/
286 
287 /* The PDL can deassert the IRQ status during Cy_SMIF_Interrupt which prevents _cyhal_qspi_get_irq_obj()
288  * from working properly in _cyhal_qspi_cb_wrapper on devices with muxed IRQs, because they can't tell
289  * at that point which system IRQ caused the CPU IRQ. So we need to save this value at the beginning of the
290  * IRQ handler when we are able to determine what it is */
291 static volatile cyhal_qspi_t* _cyhal_qspi_irq_obj = NULL;
292 
_cyhal_qspi_cb_wrapper(uint32_t event)293 static void _cyhal_qspi_cb_wrapper(uint32_t event)
294 {
295     cyhal_qspi_event_t hal_event = CYHAL_QSPI_EVENT_NONE;
296     if (event == CY_SMIF_SEND_CMPLT)
297         hal_event = CYHAL_QSPI_IRQ_TRANSMIT_DONE;
298     else if (event == CY_SMIF_REC_CMPLT)
299         hal_event = CYHAL_QSPI_IRQ_RECEIVE_DONE;
300 
301     cyhal_qspi_t *obj = (cyhal_qspi_t *)_cyhal_qspi_irq_obj;
302 
303     if ((obj->irq_cause & (uint32_t)hal_event) > 0) // Make sure a user requested event is set before calling
304     {
305         cyhal_qspi_event_callback_t callback = (cyhal_qspi_event_callback_t) obj->callback_data.callback;
306         callback(obj->callback_data.callback_arg, hal_event);
307     }
308 }
309 
310 /*******************************************************************************
311 *       (Internal) Interrupt Service Routines
312 *******************************************************************************/
313 
314 /* Interrupt call, needed for SMIF Async operations */
_cyhal_qspi_irq_handler(void)315 static void _cyhal_qspi_irq_handler(void)
316 {
317     /* Save the old value and store it aftewards in case we get into a nested IRQ situation */
318     /* Safe to cast away volatile because we don't expect this pointer to be changed while we're in here, they
319      * just might change where the original pointer points */
320     cyhal_qspi_t* old_irq_obj = (cyhal_qspi_t*)_cyhal_qspi_irq_obj;
321     _cyhal_qspi_irq_obj = (cyhal_qspi_t*) _cyhal_qspi_get_irq_obj();
322     cyhal_qspi_t* obj = (cyhal_qspi_t*)_cyhal_qspi_irq_obj;
323 
324     Cy_SMIF_Interrupt(obj->base, &(obj->context));
325 
326     _cyhal_qspi_irq_obj = old_irq_obj;
327 }
328 
329 /*******************************************************************************
330 *       (Internal) QSPI Pin Related Functions
331 *******************************************************************************/
332 
333 /* Check if pin valid as resource and reserve it */
_cyhal_qspi_check_pin_and_reserve(const cyhal_resource_pin_mapping_t * mapping,uint8_t drive_mode)334 static inline cy_rslt_t _cyhal_qspi_check_pin_and_reserve(const cyhal_resource_pin_mapping_t *mapping, uint8_t drive_mode)
335 {
336     // Mbed calls qspi_init multiple times without calling qspi_free to update the QSPI frequency/mode.
337     // As a result, we can't worry about resource reservation if running through mbed.
338 #ifndef __MBED__
339     cy_rslt_t result = _cyhal_utils_reserve_and_connect(mapping, drive_mode);
340 #else
341     cy_rslt_t result = cyhal_connect_pin(mapping, drive_mode);
342 #endif
343 
344     return result;
345 }
346 
347 /*******************************************************************************
348 *       (Internal) QSPI Config Related Functions
349 *******************************************************************************/
350 
351 /* Translates HAL bus width to PDL bus width */
_cyhal_qspi_convert_bus_width(cyhal_qspi_bus_width_t bus_width)352 static cy_en_smif_txfr_width_t _cyhal_qspi_convert_bus_width(cyhal_qspi_bus_width_t bus_width)
353 {
354     cy_en_smif_txfr_width_t cyhal_bus_width;
355 
356     switch (bus_width)
357     {
358         case CYHAL_QSPI_CFG_BUS_SINGLE:
359             cyhal_bus_width = CY_SMIF_WIDTH_SINGLE;
360             break;
361         case CYHAL_QSPI_CFG_BUS_DUAL:
362             cyhal_bus_width = CY_SMIF_WIDTH_DUAL;
363             break;
364         case CYHAL_QSPI_CFG_BUS_QUAD:
365             cyhal_bus_width = CY_SMIF_WIDTH_QUAD;
366             break;
367         case CYHAL_QSPI_CFG_BUS_OCTAL:
368             cyhal_bus_width = CY_SMIF_WIDTH_OCTAL;
369             break;
370         default:
371             cyhal_bus_width = CY_SMIF_WIDTH_SINGLE;
372     }
373 
374     return cyhal_bus_width;
375 }
376 
_cyhal_qspi_check_command_struct(const cyhal_qspi_command_t * qspi_command)377 static cy_rslt_t _cyhal_qspi_check_command_struct(const cyhal_qspi_command_t *qspi_command)
378 {
379     #if (CY_IP_MXSMIF_VERSION < 3)
380     if (((!qspi_command->instruction.disabled) && (qspi_command->instruction.data_rate == CYHAL_QSPI_DATARATE_DDR)) ||
381         ((!qspi_command->address.disabled) && (qspi_command->address.data_rate == CYHAL_QSPI_DATARATE_DDR)) ||
382         ((!qspi_command->mode_bits.disabled) && (qspi_command->mode_bits.data_rate == CYHAL_QSPI_DATARATE_DDR)) ||
383         ((qspi_command->dummy_cycles.dummy_count != 0) && (qspi_command->dummy_cycles.data_rate == CYHAL_QSPI_DATARATE_DDR)) ||
384         (qspi_command->data.data_rate == CYHAL_QSPI_DATARATE_DDR))
385     {
386         /* DDR datarate is not supported by used SMIF IP block */
387         return CYHAL_QSPI_RSLT_ERR_DATARATE;
388     }
389     if (qspi_command->instruction.two_byte_cmd)
390     {
391         /* Two byte instuction is not supported on current SMIF IP block */
392         return CYHAL_QSPI_RSLT_ERR_INSTRUCTION;
393     }
394     if ((qspi_command->dummy_cycles.dummy_count != 0) && (qspi_command->dummy_cycles.bus_width != CYHAL_QSPI_CFG_BUS_SINGLE))
395     {
396         /* Bus width parameter for dummy cycles can only be 'single' for current version of SMIF IP block */
397         return CYHAL_QSPI_RSLT_ERR_DUMMY_CYCLES;
398     }
399     #else /* CY_IP_MXSMIF_VERSION < 3 or other */
400     CY_UNUSED_PARAMETER(qspi_command);
401     #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
402     return CY_RSLT_SUCCESS;
403 }
404 
_cyhal_qspi_uint32_to_byte_array(uint32_t value,uint8_t * byteArray,uint32_t startPos,uint32_t size)405 static void _cyhal_qspi_uint32_to_byte_array(uint32_t value, uint8_t *byteArray, uint32_t startPos, uint32_t size)
406 {
407     do
408     {
409         size--;
410         byteArray[size + startPos] = (uint8_t)(value & 0xFF);
411         value >>= 0x08;
412     } while (size > 0);
413 }
414 
415 /* cyhal_qspi_size_t to number bytes */
_cyhal_qspi_get_size(cyhal_qspi_size_t hal_size)416 static inline uint32_t _cyhal_qspi_get_size(cyhal_qspi_size_t hal_size)
417 {
418     return ((uint32_t)hal_size >> 3); /* convert bits to bytes */
419 }
420 
421 /* Sends QSPI command with certain set of data */
_cyhal_qspi_command_transfer(cyhal_qspi_t * obj,const cyhal_qspi_command_t * command,uint32_t addr,bool endOfTransfer)422 static cy_rslt_t _cyhal_qspi_command_transfer(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command,
423     uint32_t addr, bool endOfTransfer)
424 {
425     /* max address size is 4 bytes and max mode bits size is 4 bytes */
426     uint8_t cmd_param[8] = {0};
427     uint32_t start_pos = 0;
428     uint32_t addr_size = 0;
429     uint32_t mode_bits_size = 0;
430     cy_en_smif_txfr_width_t bus_width = CY_SMIF_WIDTH_SINGLE;
431     #if (CY_IP_MXSMIF_VERSION >= 3)
432     cy_en_smif_data_rate_t data_rate = CY_SMIF_SDR;
433     #endif /* CY_IP_MXSMIF_VERSION >= 3 */
434 
435     cy_rslt_t result = _cyhal_qspi_check_command_struct(command);
436 
437     if (CY_RSLT_SUCCESS == result)
438     {
439         /* Does not support different bus_width for address and mode bits.
440         * bus_width is selected based on what (address or mode bits) is enabled.
441         * If both are enabled, bus_width of mode bits is selected
442         * It is either possible to support 1 byte mode bits with different bus_width
443         * by sending the mode byte as command as done in Cy_SMIF_Memslot_CmdRead()
444         * in cyhal_smif_memslot.c or support multiple bytes of mode bits with same bus_width
445         * as address by passing the mode bytes as cmd_param to Cy_SMIF_TransmitCommand().
446         * Second approach is implemented here. This restriction is because of the way
447         * PDL API is implemented.
448         */
449 
450         if (!command->address.disabled && !command->mode_bits.disabled)
451         {
452             if (command->address.bus_width != command->mode_bits.bus_width)
453             {
454                 result = CYHAL_QSPI_RSLT_ERR_BUS_WIDTH;
455             }
456             #if (CY_IP_MXSMIF_VERSION >= 3)
457             else if (command->address.data_rate != command->mode_bits.data_rate)
458             {
459                 result = CYHAL_QSPI_RSLT_ERR_DATARATE;
460             }
461             #endif /* CY_IP_MXSMIF_VERSION >= 3 */
462         }
463 
464         if (CY_RSLT_SUCCESS == result)
465         {
466             if (!command->address.disabled)
467             {
468                 addr_size = _cyhal_qspi_get_size(command->address.size);
469                 _cyhal_qspi_uint32_to_byte_array(addr, cmd_param, start_pos, addr_size);
470                 start_pos += addr_size;
471                 bus_width = _cyhal_qspi_convert_bus_width(command->address.bus_width);
472                 #if (CY_IP_MXSMIF_VERSION >= 3)
473                 data_rate = (cy_en_smif_data_rate_t)command->address.data_rate;
474                 #endif /* CY_IP_MXSMIF_VERSION >= 3 */
475             }
476 
477             if (!command->mode_bits.disabled)
478             {
479                 mode_bits_size = _cyhal_qspi_get_size(command->mode_bits.size);
480                 _cyhal_qspi_uint32_to_byte_array(command->mode_bits.value, cmd_param, start_pos, mode_bits_size);
481                 bus_width = _cyhal_qspi_convert_bus_width(command->mode_bits.bus_width);
482                 #if (CY_IP_MXSMIF_VERSION >= 3)
483                 data_rate = (cy_en_smif_data_rate_t)command->mode_bits.data_rate;
484                 #endif /* CY_IP_MXSMIF_VERSION >= 3 */
485             }
486 
487             uint32_t cmpltTxfr = ((endOfTransfer) ? 1UL : 0UL);
488             #if (CY_IP_MXSMIF_VERSION < 3)
489             result = (cy_rslt_t)Cy_SMIF_TransmitCommand(obj->base, (uint8_t)(command->instruction.value & 0xFF),
490                         _cyhal_qspi_convert_bus_width(command->instruction.bus_width), cmd_param,
491                         (addr_size + mode_bits_size), bus_width, obj->slave_select, cmpltTxfr, &obj->context);
492             #else
493             result = (cy_rslt_t)Cy_SMIF_TransmitCommand_Ext(obj->base, command->instruction.value,
494                         command->instruction.two_byte_cmd, _cyhal_qspi_convert_bus_width(command->instruction.bus_width),
495                         (cy_en_smif_data_rate_t)command->instruction.data_rate, cmd_param, (addr_size + mode_bits_size),
496                         bus_width, data_rate, obj->slave_select, cmpltTxfr, &obj->context);
497             #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
498         }
499     }
500     return result;
501 }
502 
_cyhal_qspi_slave_idx_to_smif_ss(uint8_t ssel_idx)503 static inline cy_en_smif_slave_select_t _cyhal_qspi_slave_idx_to_smif_ss(uint8_t ssel_idx)
504 {
505     return (cy_en_smif_slave_select_t)(1 << ssel_idx);
506 }
507 
508 /* Checks, that user provided all needed pins and returns max bus width */
_cyhal_qspi_check_user_pins(const cyhal_qspi_slave_pin_config_t * pin_set,cyhal_qspi_bus_width_t * max_width)509 static cy_rslt_t _cyhal_qspi_check_user_pins(const cyhal_qspi_slave_pin_config_t *pin_set, cyhal_qspi_bus_width_t *max_width)
510 {
511     cy_rslt_t result = CY_RSLT_SUCCESS;
512 
513 #if _CYHAL_QSPI_DATA8_PRESENT
514     if (NC != pin_set->io[4])
515     {
516         *max_width = CYHAL_QSPI_CFG_BUS_OCTAL;
517     }
518     else
519 #endif
520     if (NC != pin_set->io[2])
521     {
522         *max_width = CYHAL_QSPI_CFG_BUS_QUAD;
523     }
524     else if (NC != pin_set->io[1])
525     {
526         *max_width = CYHAL_QSPI_CFG_BUS_DUAL;
527     }
528     else
529     {
530         *max_width = CYHAL_QSPI_CFG_BUS_SINGLE;
531     }
532 
533     for (uint8_t i = 1; i <= _CYHAL_QSPI_MAX_DATA_PINS; i++)
534     {
535         /* Pins with index lower than width must be provided, pins above should be NC */
536         if ((NC == pin_set->io[i-1]) != (i > *max_width))
537         {
538             result = CYHAL_QSPI_RSLT_ERR_PIN;
539         }
540     }
541 
542     return result;
543 }
544 
545 /* Based on ssel pin chosen, determines SMIF slave select parameter and pin mapping */
_cyhal_qspi_get_slaveselect(cyhal_gpio_t ssel,uint8_t * ssel_idx)546 static const cyhal_resource_pin_mapping_t *_cyhal_qspi_get_slaveselect(cyhal_gpio_t ssel, uint8_t *ssel_idx)
547 {
548 #if _CYHAL_QSPI_SEL1 || _CYHAL_QSPI_SEL2 || _CYHAL_QSPI_SEL3
549     bool pin_found = false;
550 #endif
551     const cyhal_resource_pin_mapping_t *pin_mapping = _CYHAL_UTILS_GET_RESOURCE(ssel, cyhal_pin_map_smif_spi_select0);
552     if (NULL != pin_mapping)
553     {
554 #if _CYHAL_QSPI_SEL1 || _CYHAL_QSPI_SEL2 || _CYHAL_QSPI_SEL3
555         pin_found = true;
556 #endif
557         /* Provided by user ssel is related to Slave # 0 */
558         *ssel_idx = 0;
559     }
560 #if _CYHAL_QSPI_SEL1
561     if (!pin_found)
562     {
563         pin_mapping = _CYHAL_UTILS_GET_RESOURCE(ssel, cyhal_pin_map_smif_spi_select1);
564         if (NULL != pin_mapping)
565         {
566             pin_found = true;
567             /* Provided by user ssel is related to Slave # 1 */
568             *ssel_idx = 1;
569         }
570     }
571 #endif
572 #if _CYHAL_QSPI_SEL2
573     if (!pin_found)
574     {
575         pin_mapping = _CYHAL_UTILS_GET_RESOURCE(ssel, cyhal_pin_map_smif_spi_select2);
576         if (NULL != pin_mapping)
577         {
578             pin_found = true;
579             /* Provided by user ssel is related to Slave # 2 */
580             *ssel_idx = 2;
581         }
582     }
583 #endif
584 #if _CYHAL_QSPI_SEL3
585     if (!pin_found)
586     {
587         pin_mapping = _CYHAL_UTILS_GET_RESOURCE(ssel, cyhal_pin_map_smif_spi_select3);
588         if (NULL != pin_mapping)
589         {
590             pin_found = true;
591             /* Provided by user ssel is related to Slave # 3 */
592             *ssel_idx = 3;
593         }
594     }
595 #endif
596 
597     return pin_mapping;
598 }
599 
600 /* Based on data pins chosen, determines SMIF data select parameter */
_cyhal_qspi_get_dataselect(cyhal_gpio_t io0,cy_en_smif_data_select_t * data_select,uint8_t * offset)601 static const cyhal_resource_pin_mapping_t *_cyhal_qspi_get_dataselect(cyhal_gpio_t io0, cy_en_smif_data_select_t *data_select, uint8_t *offset)
602 {
603     bool pin_found = false;
604     const cyhal_resource_pin_mapping_t *pin_mapping = _CYHAL_UTILS_GET_RESOURCE(io0, cyhal_pin_map_smif_spi_data0);
605     if (NULL != pin_mapping)
606     {
607         pin_found = true;
608         *data_select = CY_SMIF_DATA_SEL0;
609         *offset = 0;
610     }
611     if (!pin_found)
612     {
613         pin_mapping = _CYHAL_UTILS_GET_RESOURCE(io0, cyhal_pin_map_smif_spi_data2);
614         if (NULL != pin_mapping)
615         {
616             pin_found = true;
617             *data_select = CY_SMIF_DATA_SEL1;
618             *offset = 2;
619         }
620     }
621 #if _CYHAL_QSPI_DATA8_PRESENT
622     if (!pin_found)
623     {
624         pin_mapping = _CYHAL_UTILS_GET_RESOURCE(io0, cyhal_pin_map_smif_spi_data4);
625         if (NULL != pin_mapping)
626         {
627             pin_found = true;
628             *data_select = CY_SMIF_DATA_SEL2;
629             *offset = 4;
630         }
631     }
632     if (!pin_found)
633     {
634         pin_mapping = _CYHAL_UTILS_GET_RESOURCE(io0, cyhal_pin_map_smif_spi_data6);
635         if (NULL != pin_mapping)
636         {
637             pin_found = true;
638             *data_select = CY_SMIF_DATA_SEL3;
639             *offset = 6;
640         }
641     }
642 #endif
643     return pin_mapping;
644 }
645 
646 /*******************************************************************************
647 *       Functions
648 *******************************************************************************/
649 
_cyhal_qspi_slave_select_check_reserve(cyhal_qspi_t * obj,cyhal_gpio_t ssel,uint8_t * found_idx,bool reserve_n_connect)650 static cy_rslt_t _cyhal_qspi_slave_select_check_reserve(cyhal_qspi_t *obj, cyhal_gpio_t ssel, uint8_t *found_idx,
651                                                         bool reserve_n_connect)
652 {
653     CY_ASSERT(NULL != obj);
654     const cyhal_resource_pin_mapping_t *ssel_map = _cyhal_qspi_get_slaveselect(ssel, found_idx);
655     /* Found ssel map is not null and belong to same block as obj->resource */
656     if ((NULL == ssel_map) || !_cyhal_utils_map_resource_equal(&obj->resource, ssel_map, true))
657     {
658         return CYHAL_QSPI_RSLT_ERR_CANNOT_CONFIG_SSEL;
659     }
660     /* Specified SSEL is already configured, nothing to do. */
661     if (NC != obj->pin_ssel[*found_idx])
662     {
663         return CY_RSLT_SUCCESS;
664     }
665     /* No problems with pins, proceeding to reservation if reserve_n_connect is true */
666     /* If reserve_n_connect is false, it is assumed that pins are reserved and initialized by configurator - generated
667     *   code */
668     cy_rslt_t result = reserve_n_connect
669         ? _cyhal_qspi_check_pin_and_reserve(ssel_map, CYHAL_PIN_MAP_DRIVE_MODE_SMIF_SPI_SELECT0)
670         : CY_RSLT_SUCCESS;
671     if (CY_RSLT_SUCCESS == result)
672     {
673         obj->pin_ssel[*found_idx] = ssel;
674     }
675     return result;
676 }
677 
678 /* Checks that provided pins are correct, store them in the object and return data select */
_cyhal_qspi_process_pin_set(cyhal_qspi_t * obj,const cyhal_qspi_slave_pin_config_t * pin_set,cy_en_smif_data_select_t * data_select,uint8_t * found_ssel_idx,bool reserve_n_connect)679 static cy_rslt_t _cyhal_qspi_process_pin_set(cyhal_qspi_t *obj, const cyhal_qspi_slave_pin_config_t *pin_set,
680     cy_en_smif_data_select_t *data_select, uint8_t *found_ssel_idx, bool reserve_n_connect)
681 {
682     CY_ASSERT(NULL != obj);
683     CY_ASSERT(NULL != pin_set);
684 
685     cyhal_qspi_bus_width_t max_width;
686     cy_rslt_t result = _cyhal_qspi_check_user_pins(pin_set, &max_width);
687 
688     uint8_t pin_offset = 0;
689     const cyhal_resource_pin_mapping_t *io_maps[_CYHAL_QSPI_MAX_DATA_PINS];
690     for (uint8_t i = 0; i < _CYHAL_QSPI_MAX_DATA_PINS; i++)
691     {
692         io_maps[i] = NULL;
693     }
694     const size_t data_pin_map_sizes[_CYHAL_QSPI_MAX_DATA_PINS - 1] = // Must compute sizes here since we can't get them from the map pointers
695     {
696         sizeof(cyhal_pin_map_smif_spi_data1) / sizeof(cyhal_resource_pin_mapping_t),
697         sizeof(cyhal_pin_map_smif_spi_data2) / sizeof(cyhal_resource_pin_mapping_t),
698         sizeof(cyhal_pin_map_smif_spi_data3) / sizeof(cyhal_resource_pin_mapping_t),
699 #if _CYHAL_QSPI_DATA8_PRESENT
700         sizeof(cyhal_pin_map_smif_spi_data4) / sizeof(cyhal_resource_pin_mapping_t),
701         sizeof(cyhal_pin_map_smif_spi_data5) / sizeof(cyhal_resource_pin_mapping_t),
702         sizeof(cyhal_pin_map_smif_spi_data6) / sizeof(cyhal_resource_pin_mapping_t),
703         sizeof(cyhal_pin_map_smif_spi_data7) / sizeof(cyhal_resource_pin_mapping_t),
704 #endif
705     };
706     const cyhal_resource_pin_mapping_t *data_pin_maps[_CYHAL_QSPI_MAX_DATA_PINS - 1] = // Not used to get the map for data pin 0
707     {
708         cyhal_pin_map_smif_spi_data1,
709         cyhal_pin_map_smif_spi_data2,
710         cyhal_pin_map_smif_spi_data3,
711 #if _CYHAL_QSPI_DATA8_PRESENT
712         cyhal_pin_map_smif_spi_data4,
713         cyhal_pin_map_smif_spi_data5,
714         cyhal_pin_map_smif_spi_data6,
715         cyhal_pin_map_smif_spi_data7,
716 #endif
717     };
718 
719     if (CY_RSLT_SUCCESS == result)
720     {
721         const cyhal_resource_pin_mapping_t *tmp_io_map =
722                 _cyhal_qspi_get_dataselect(pin_set->io[0], data_select, &pin_offset);
723         io_maps[pin_offset] = tmp_io_map;
724         if ( NULL == io_maps[pin_offset] ||
725             !_cyhal_utils_map_resource_equal(&obj->resource, io_maps[pin_offset],true))
726         {
727             result = CYHAL_QSPI_RSLT_ERR_PIN;
728         }
729     }
730 
731     if (CY_RSLT_SUCCESS == result)
732     {
733         /* DATA_SEL 1 and DATA_SEL 3 are illegal when using Quad SPI
734         *  DATA SEL 1, DATA SEL 2 and DATA SEL 3 are illegal when using Octal SPI */
735         if (((CYHAL_QSPI_CFG_BUS_QUAD == max_width) &&
736                 ((CY_SMIF_DATA_SEL1 == *data_select) || (CY_SMIF_DATA_SEL3 == *data_select))) ||
737             ((CYHAL_QSPI_CFG_BUS_OCTAL == max_width) && (*data_select >= CY_SMIF_DATA_SEL1)))
738         {
739             result = CYHAL_QSPI_RSLT_ERR_DATA_SEL;
740         }
741     }
742 
743     if (CY_RSLT_SUCCESS == result)
744     {
745         /* Check that all data pins (but not the first one, which is covered already) are valid and belong
746         *  to same instance */
747         for (uint8_t i = pin_offset + 1; i < pin_offset + max_width; i++)
748         {
749             io_maps[i] = _cyhal_utils_get_resource(pin_set->io[i-pin_offset], data_pin_maps[i-1], data_pin_map_sizes[i-1],
750                                 NULL, false);
751             if (NULL == io_maps[i] || !_cyhal_utils_map_resource_equal(&obj->resource, io_maps[i],true))
752             {
753                 result = CYHAL_QSPI_RSLT_ERR_PIN;
754                 break;
755             }
756         }
757     }
758 
759     if (CY_RSLT_SUCCESS == result)
760     {
761         result = _cyhal_qspi_slave_select_check_reserve(obj, pin_set->ssel, found_ssel_idx, reserve_n_connect);
762     }
763 
764     if (CY_RSLT_SUCCESS == result)
765     {
766         /* reserve the io pins */
767         for (uint8_t i = pin_offset; (i < pin_offset + max_width) && (result == CY_RSLT_SUCCESS); i++)
768         {
769             if ((NC != pin_set->io[i-pin_offset]) && (NC == obj->pin_io[i]))
770             {
771                 if (reserve_n_connect)
772                 {
773                     result = _cyhal_qspi_check_pin_and_reserve(io_maps[i], CYHAL_PIN_MAP_DRIVE_MODE_SMIF_SPI_DATA0);
774                 }
775                 if (CY_RSLT_SUCCESS == result)
776                 {
777                     obj->pin_io[i] = pin_set->io[i-pin_offset];
778                 }
779             }
780         }
781     }
782 
783     return result;
784 }
785 
786 
_cyhal_qspi_init_common(cyhal_qspi_t * obj,const cyhal_qspi_configurator_t * cfg,uint32_t hz)787 static cy_rslt_t _cyhal_qspi_init_common(cyhal_qspi_t *obj, const cyhal_qspi_configurator_t *cfg, uint32_t hz)
788 {
789     /* Explicitly marked not allocated resources as invalid to prevent freeing them. */
790     memset(obj, 0, sizeof(cyhal_qspi_t));
791     obj->resource.type = CYHAL_RSC_INVALID;
792     obj->is_clock_owned = false;
793 
794     obj->dc_configured = (NULL != cfg->resource);
795     if ((obj->dc_configured) &&
796         (cfg->config->mode != CY_SMIF_NORMAL ||
797         /* Bits representation of interrupts (msb to lsb):
798             _MEMORY_MODE_ALIGMENT_ERROR, _RX_DATA_FIFO_UNDERFLOW, _TX_COMMAND_FIFO_OVERFLOW, _TX_DATA_FIFO_OVERFLOW,
799             _RX_FIFO_TRIGEER_LEVEL, _TX_FIFO_TRIGEER_LEVEL */
800         ((cfg->irqs & 0x3F) != 0) ||
801         /* Bits representation of activated DMA outputs (msb to lsb):
802             _RX_DMA_TRIGGER_OUT_USED, _TX_DMA_TRIGGER_OUT_USED */
803         (cfg->dmas & 0x3) != 0))
804     {
805         /* List of SMIF personality items, which are currently not supported in QSPI HAL driver:
806             - XIP (eXecute In Place) mode
807             - Memory Mode Alignment Error interrupt
808             - RX Data FIFO Underflow interrupt
809             - TX Command FIFO Overflow
810             - TX Data FIFO Overflow interrupt
811             - RX FIFO Level Trigger interrupt
812             - TX FIFO Level Trigger interrupt
813             - RX DMA Trigger
814             - TX DMA Trigger
815         */
816         return CYHAL_QSPI_RSLT_ERR_UNSUPPORTED;
817     }
818 
819     cyhal_gpio_t ssel = NC;
820     size_t found_ssel_idx_cfg = 0;
821     for (size_t ssel_idx = 0; ssel_idx < sizeof(cfg->gpios.ssel) / sizeof(cfg->gpios.ssel[0]); ++ssel_idx)
822     {
823         if (NC != cfg->gpios.ssel[ssel_idx])
824         {
825             ssel = cfg->gpios.ssel[ssel_idx];
826             found_ssel_idx_cfg = ssel_idx;
827             break;
828         }
829     }
830 
831     cy_rslt_t result = CY_RSLT_SUCCESS;
832 #if (CY_IP_MXSMIF_VERSION >= 4)
833     if(cfg->gpios.sclk != NC)
834     {
835         result = CYHAL_QSPI_RSLT_ERR_PIN;
836     }
837 #else
838     const cyhal_resource_pin_mapping_t *sclk_map = _CYHAL_UTILS_GET_RESOURCE(cfg->gpios.sclk, cyhal_pin_map_smif_spi_clk);
839     /* Can't work without sclk pin */
840     if (NULL == sclk_map)
841     {
842         result = CYHAL_QSPI_RSLT_ERR_PIN;
843     }
844     if ((CY_RSLT_SUCCESS == result) && (false == obj->dc_configured))
845     {
846         result = _cyhal_qspi_check_pin_and_reserve(sclk_map, CYHAL_PIN_MAP_DRIVE_MODE_SMIF_SPI_CLK);
847     }
848 #endif
849     if (CY_RSLT_SUCCESS == result)
850     {
851         obj->pin_sclk = cfg->gpios.sclk;
852 
853         for (size_t i = 0; i < SMIF_CHIP_TOP_SPI_SEL_NR; ++i)
854         {
855             obj->pin_ssel[i] = NC;
856         }
857         for (size_t i = 0; i < _CYHAL_QSPI_MAX_DATA_PINS; ++i)
858         {
859             obj->pin_io[i] = NC;
860         }
861     }
862 
863     cy_en_smif_data_select_t data_select;
864     uint8_t found_ssel_idx;
865 
866     cyhal_qspi_slave_pin_config_t pin_set;
867     pin_set.ssel = ssel;
868     memcpy(pin_set.io, cfg->gpios.io, sizeof(cfg->gpios.io));
869     const cyhal_resource_pin_mapping_t *ssel_map;
870     if (CY_RSLT_SUCCESS == result)
871     {
872         ssel_map = _cyhal_qspi_get_slaveselect(ssel, &found_ssel_idx);
873         if(ssel_map == NULL)
874         {
875             result = CYHAL_QSPI_RSLT_ERR_PIN;
876         }
877     }
878     if (CY_RSLT_SUCCESS == result)
879     {
880         if (obj->dc_configured)
881         {
882             obj->resource = *cfg->resource;
883         }
884         else
885         {
886             cyhal_resource_inst_t rsc = { CYHAL_RSC_SMIF, ssel_map->block_num, ssel_map->channel_num };
887         #ifndef __MBED__
888             // Mbed calls qspi_init multiple times without calling qspi_free to update the QSPI frequency/mode.
889             // As a result, we won't worry about resource reservation if running through mbed.
890             result = cyhal_hwmgr_reserve(&rsc);
891             if (CY_RSLT_SUCCESS == result)
892         #endif
893             {
894                 obj->resource = rsc;
895             }
896         }
897     }
898 
899     if (CY_RSLT_SUCCESS == result)
900     {
901         result = _cyhal_qspi_process_pin_set(obj, &pin_set, &data_select, &found_ssel_idx, !obj->dc_configured);
902     }
903 
904 
905     if (CY_RSLT_SUCCESS == result)
906     {
907         obj->base = _cyhal_qspi_base_addresses[obj->resource.block_num];
908     }
909 
910     if (CY_RSLT_SUCCESS == result)
911     {
912         if (NULL != cfg->clock)
913         {
914             /* Clock is provided by configuration */
915             if (cfg->clock->block == CYHAL_CLOCK_BLOCK_HF)
916             {
917                 obj->clock = *cfg->clock;
918                 /* obj->is_clock_owned is false already, so no need to assign it */
919             }
920             else
921             {
922                 /* Incorrect shared clock was provided by user. */
923                 result = CYHAL_QSPI_RSLT_ERR_CLOCK;
924             }
925         }
926         else
927         {
928             /* No clock was provided by configuration, so allocating it */
929 
930             // The hardware is generally going to be hardwired to an hfclk, which has very limited divider options. In the event
931             // that we're hooked up a PERI divider, we don't have any particular expectations about its width - so just ask for 8-bit
932             result = _cyhal_utils_allocate_clock(&(obj->clock), &(obj->resource), CYHAL_CLOCK_BLOCK_PERIPHERAL_8BIT, true);
933             obj->is_clock_owned = (result == CY_RSLT_SUCCESS);
934         }
935     }
936 
937     if (obj->is_clock_owned)
938     {
939         if (CY_RSLT_SUCCESS == result)
940         {
941             result = cyhal_qspi_set_frequency(obj, hz);
942         }
943 
944         if (CY_RSLT_SUCCESS == result)
945         {
946             result = cyhal_clock_set_enabled(&(obj->clock), true, true);
947         }
948     }
949 
950     if (CY_RSLT_SUCCESS == result)
951     {
952         result = (cy_rslt_t) Cy_SMIF_Init(obj->base, cfg->config, _CYHAL_QSPI_TIMEOUT_10_MS, &obj->context);
953     }
954 
955     if (CY_RSLT_SUCCESS == result)
956     {
957         /* Configure first SSEL, that was found in cfg->gpios and make it active */
958         obj->slave_select = _cyhal_qspi_slave_idx_to_smif_ss(found_ssel_idx);
959         Cy_SMIF_SetDataSelect(obj->base, obj->slave_select, data_select);
960 
961         /* found_ssel_idx_cfg and below are already processed, no reason to start from index #0 */
962         size_t ssel_idx = found_ssel_idx_cfg;
963         /* Process rest of ssel, that are provided by cfg->gpios */
964         while ((CY_RSLT_SUCCESS == result) && ((ssel_idx + 1) < (sizeof(cfg->gpios.ssel) / sizeof(cfg->gpios.ssel[0]))))
965         {
966             ++ssel_idx;
967             if (NC != cfg->gpios.ssel[ssel_idx])
968             {
969                 pin_set.ssel = cfg->gpios.ssel[ssel_idx];
970                 result = _cyhal_qspi_process_pin_set(obj, &pin_set, &data_select, &found_ssel_idx, !obj->dc_configured);
971                 if (result == CY_RSLT_SUCCESS)
972                 {
973                     Cy_SMIF_SetDataSelect(obj->base, _cyhal_qspi_slave_idx_to_smif_ss(found_ssel_idx), data_select);
974                 }
975             }
976         }
977     }
978 
979     if (CY_RSLT_SUCCESS == result)
980     {
981         Cy_SMIF_Enable(obj->base, &obj->context);
982 
983         obj->callback_data.callback = NULL;
984         obj->callback_data.callback_arg = NULL;
985         obj->irq_cause = CYHAL_QSPI_EVENT_NONE;
986         _cyhal_qspi_config_structs[obj->resource.block_num] = obj;
987         #if CYHAL_DRIVER_AVAILABLE_SYSPM
988         obj->pm_transition_pending = false;
989         obj->pm_callback.callback = &_cyhal_qspi_pm_callback;
990         obj->pm_callback.states = (cyhal_syspm_callback_state_t)(CYHAL_SYSPM_CB_CPU_DEEPSLEEP | CYHAL_SYSPM_CB_CPU_DEEPSLEEP_RAM | CYHAL_SYSPM_CB_SYSTEM_HIBERNATE);
991         obj->pm_callback.args = obj;
992         obj->pm_callback.next = NULL;
993         obj->pm_callback.ignore_modes = CYHAL_SYSPM_AFTER_DS_WFI_TRANSITION;
994         _cyhal_syspm_register_peripheral_callback(&(obj->pm_callback));
995         #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
996 
997         _cyhal_irq_register(_cyhal_qspi_irq_n[obj->resource.block_num], CYHAL_ISR_PRIORITY_DEFAULT, _cyhal_qspi_irq_handler);
998         _cyhal_irq_enable(_cyhal_qspi_irq_n[obj->resource.block_num]);
999     }
1000 
1001     if (CY_RSLT_SUCCESS != result)
1002     {
1003         cyhal_qspi_free(obj);
1004     }
1005 
1006     return result;
1007 }
1008 
cyhal_qspi_init(cyhal_qspi_t * obj,cyhal_gpio_t sclk,const cyhal_qspi_slave_pin_config_t * pin_set,uint32_t hz,uint8_t mode,cyhal_clock_t * clk)1009 cy_rslt_t cyhal_qspi_init(
1010     cyhal_qspi_t *obj, cyhal_gpio_t sclk, const cyhal_qspi_slave_pin_config_t *pin_set, uint32_t hz, uint8_t mode,
1011     cyhal_clock_t *clk)
1012 {
1013     CY_ASSERT(NULL != obj);
1014     CY_ASSERT(NULL != pin_set);
1015 
1016     /* mode (CPOL and CPHA) are not supported in CAT1 */
1017     CY_UNUSED_PARAMETER(mode);
1018 
1019 #if defined(CY_DEVICE_CYW20829)
1020     if (NULL == clk)
1021     {
1022         /* Only user-provided clock is supported by 20829 QSPI. Please refer to device-specific
1023             "section_hal_impl_qspi_init_clock_20829" documentation section for details. */
1024 
1025         return CYHAL_QSPI_RSLT_ERR_UNSUPPORTED;
1026     }
1027 #endif /* defined(CY_DEVICE_CYW20829) */
1028 
1029     /* Default QSPI configuration */
1030     const cy_stc_smif_config_t config =
1031     {
1032         .mode = (uint32_t)CY_SMIF_NORMAL,
1033         .deselectDelay = _CYHAL_QSPI_DESELECT_DELAY,
1034 #if (CY_IP_MXSMIF_VERSION >= 2)
1035         .rxClockSel = (uint32_t)CY_SMIF_SEL_INVERTED_FEEDBACK_CLK,
1036 #else
1037         .rxClockSel = (uint32_t)CY_SMIF_SEL_INV_INTERNAL_CLK,
1038 #endif
1039         .blockEvent = (uint32_t)CY_SMIF_BUS_ERROR,
1040     };
1041 
1042     const cyhal_qspi_configurator_t cfg = {
1043         .resource = NULL,
1044         .config = &config,
1045         .clock = clk,
1046         .gpios = {
1047             .sclk = sclk,
1048             .ssel = { pin_set->ssel, NC, NC, NC },
1049             .io = { pin_set->io[0], pin_set->io[1], pin_set->io[2], pin_set->io[3],
1050                     pin_set->io[4], pin_set->io[5], pin_set->io[6], pin_set->io[7] }
1051         },
1052         .irqs = 0u,
1053         .dmas = 0u
1054     };
1055 
1056     return _cyhal_qspi_init_common(obj, &cfg, hz);
1057 }
1058 
cyhal_qspi_init_cfg(cyhal_qspi_t * obj,const cyhal_qspi_configurator_t * cfg)1059 cy_rslt_t cyhal_qspi_init_cfg(cyhal_qspi_t *obj, const cyhal_qspi_configurator_t *cfg)
1060 {
1061     CY_ASSERT(NULL != obj);
1062     CY_ASSERT(NULL != cfg);
1063     CY_ASSERT(NULL != cfg->config);
1064 
1065     /* Frequency parameter is ignored when clock is provided (configurator flow, cyhal_qspi_init_cfg function) */
1066     return _cyhal_qspi_init_common(obj, cfg, 0);
1067 }
1068 
cyhal_qspi_free(cyhal_qspi_t * obj)1069 void cyhal_qspi_free(cyhal_qspi_t *obj)
1070 {
1071     if (CYHAL_RSC_SMIF == obj->resource.type)
1072     {
1073         _cyhal_system_irq_t irqn = _cyhal_qspi_irq_n[obj->resource.block_num];
1074         _cyhal_irq_free(irqn);
1075         #if CYHAL_DRIVER_AVAILABLE_SYSPM
1076         _cyhal_syspm_unregister_peripheral_callback(&(obj->pm_callback));
1077         #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1078         if (obj->base != NULL)
1079         {
1080             Cy_SMIF_Disable(obj->base);
1081             Cy_SMIF_DeInit(obj->base);
1082             obj->base = NULL;
1083         }
1084         if (!obj->dc_configured)
1085         {
1086             cyhal_hwmgr_free(&(obj->resource));
1087         }
1088         obj->resource.type = CYHAL_RSC_INVALID;
1089     }
1090 
1091     if (!obj->dc_configured)
1092     {
1093         _cyhal_utils_release_if_used(&(obj->pin_sclk));
1094         for (uint8_t i = 0; i < SMIF_CHIP_TOP_SPI_SEL_NR; i++)
1095         {
1096             _cyhal_utils_release_if_used(&(obj->pin_ssel[i]));
1097         }
1098         for (uint8_t i = 0; (i < _CYHAL_QSPI_MAX_DATA_PINS); i++)
1099         {
1100             _cyhal_utils_release_if_used(&(obj->pin_io[i]));
1101         }
1102     }
1103 
1104     if (obj->is_clock_owned)
1105     {
1106         cyhal_clock_free(&(obj->clock));
1107         obj->is_clock_owned = false;
1108     }
1109 }
1110 
cyhal_qspi_set_frequency(cyhal_qspi_t * obj,uint32_t hz)1111 cy_rslt_t cyhal_qspi_set_frequency(cyhal_qspi_t *obj, uint32_t hz)
1112 {
1113     CY_ASSERT(NULL != obj);
1114     CY_ASSERT(hz != 0);
1115 
1116     if (obj->is_clock_owned)
1117     {
1118         const cyhal_clock_tolerance_t tolerance = { CYHAL_TOLERANCE_PERCENT, 10 };
1119 #if (CY_IP_MXSMIF_VERSION >= 2)
1120         /* SMIF ver. 2 and further divides source clock by 2 internally, so we need to request 2 times more.
1121          * Please refer to `section_hal_impl_clock_freq` implementation-specific documentation for details.
1122         */
1123         hz <<= 1;
1124 #endif /*  */
1125         return _cyhal_utils_set_clock_frequency2(&(obj->clock), hz, &tolerance);
1126     }
1127     else
1128     {
1129         /* In case of pre-configured clock, user application is responsible for configuring QSPI bus frequency.
1130         *  For all currently supported by this driver devices, output QSPI bus frequency is equal to frequency
1131         *  of provided HF clock. */
1132         return CYHAL_QSPI_RSLT_ERR_CLOCK;
1133     }
1134 }
1135 
cyhal_qspi_get_frequency(cyhal_qspi_t * obj)1136 uint32_t cyhal_qspi_get_frequency(cyhal_qspi_t *obj)
1137 {
1138     CY_ASSERT(NULL != obj);
1139     uint32_t freq = cyhal_clock_get_frequency(&(obj->clock));
1140 #if (CY_IP_MXSMIF_VERSION >= 2)
1141     /* Please refer to `section_hal_impl_clock_freq` implementation-specific documentation for details. */
1142     return freq / 2;
1143 #else
1144     return freq;
1145 #endif /* (CY_IP_MXSMIF_VERSION >= 2) or other */
1146 }
1147 
cyhal_qspi_slave_configure(cyhal_qspi_t * obj,const cyhal_qspi_slave_pin_config_t * pin_set)1148 cy_rslt_t cyhal_qspi_slave_configure(cyhal_qspi_t *obj, const cyhal_qspi_slave_pin_config_t *pin_set)
1149 {
1150     CY_ASSERT(NULL != obj);
1151     uint8_t ssel_idx = 0;
1152     cy_en_smif_data_select_t data_select;
1153     cy_rslt_t result = _cyhal_qspi_process_pin_set(obj, pin_set, &data_select, &ssel_idx, true);
1154     if (CY_RSLT_SUCCESS == result)
1155     {
1156         Cy_SMIF_SetDataSelect(obj->base, _cyhal_qspi_slave_idx_to_smif_ss(ssel_idx), data_select);
1157     }
1158     return result;
1159 }
1160 
cyhal_qspi_select_active_ssel(cyhal_qspi_t * obj,cyhal_gpio_t ssel)1161 cy_rslt_t cyhal_qspi_select_active_ssel(cyhal_qspi_t *obj, cyhal_gpio_t ssel)
1162 {
1163     CY_ASSERT(NULL != obj);
1164     for (uint8_t ssel_idx = 0; ssel_idx < SMIF_CHIP_TOP_SPI_SEL_NR; ssel_idx++)
1165     {
1166         if (ssel == obj->pin_ssel[ssel_idx])
1167         {
1168             obj->slave_select = _cyhal_qspi_slave_idx_to_smif_ss(ssel_idx);
1169             return CY_RSLT_SUCCESS;
1170         }
1171     }
1172     return CYHAL_QSPI_RSLT_ERR_CANNOT_SWITCH_SSEL;
1173 }
1174 
_cyhal_qspi_wait_for_cmd_fifo(cyhal_qspi_t * obj)1175 static cy_rslt_t _cyhal_qspi_wait_for_cmd_fifo(cyhal_qspi_t *obj)
1176 {
1177     cy_rslt_t status = CY_RSLT_SUCCESS;
1178     uint32_t timeout = _CYHAL_QSPI_TIMEOUT_10_MS;
1179     while ((Cy_SMIF_GetCmdFifoStatus(obj->base) == CY_SMIF_TX_CMD_FIFO_STATUS_RANGE) &&
1180                     (CY_RSLT_SUCCESS == status))
1181     {
1182         /* Waiting for 1 us per iteration */
1183         Cy_SysLib_DelayUs(1);
1184         --timeout;
1185         status = (0u == timeout)? CYHAL_QSPI_RSLT_ERR_TIMEOUT: CY_RSLT_SUCCESS;
1186     }
1187     return status;
1188 }
1189 
1190 /* no restriction on the value of length. This function splits the read into multiple chunked transfers. */
cyhal_qspi_read(cyhal_qspi_t * obj,const cyhal_qspi_command_t * command,uint32_t address,void * data,size_t * length)1191 cy_rslt_t cyhal_qspi_read(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, void *data, size_t *length)
1192 {
1193     #if CYHAL_DRIVER_AVAILABLE_SYSPM
1194     if (obj->pm_transition_pending)
1195     {
1196         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1197     }
1198     #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1199 
1200     cy_rslt_t status = CY_RSLT_SUCCESS;
1201     uint32_t chunk = 0;
1202     size_t read_bytes = *length;
1203 
1204     /* SMIF can read only up to 65536 bytes in one go. Split the larger read into multiple chunks */
1205     while (read_bytes > 0)
1206     {
1207         chunk = (read_bytes > _CYHAL_QSPI_MAX_RX_COUNT) ? (_CYHAL_QSPI_MAX_RX_COUNT) : read_bytes;
1208 
1209         status = _cyhal_qspi_command_transfer(obj, command, address, false);
1210 
1211         if (CY_RSLT_SUCCESS == status)
1212         {
1213             if (command->dummy_cycles.dummy_count > 0u)
1214             {
1215                 status = _cyhal_qspi_wait_for_cmd_fifo(obj);
1216                 if (CY_RSLT_SUCCESS == status)
1217                 {
1218                     #if (CY_IP_MXSMIF_VERSION < 3)
1219                     status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_cycles.dummy_count);
1220                     #else
1221                     status = (cy_rslt_t)Cy_SMIF_SendDummyCycles_Ext(obj->base,
1222                             _cyhal_qspi_convert_bus_width(command->dummy_cycles.bus_width),
1223                             (cy_en_smif_data_rate_t)command->dummy_cycles.data_rate, command->dummy_cycles.dummy_count);
1224                     #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
1225                 }
1226             }
1227 
1228             if (CY_RSLT_SUCCESS == status)
1229             {
1230                 status = _cyhal_qspi_wait_for_cmd_fifo(obj);
1231                 if (CY_RSLT_SUCCESS == status)
1232                 {
1233                     #if (CY_IP_MXSMIF_VERSION < 3)
1234                     status = (cy_rslt_t)Cy_SMIF_ReceiveDataBlocking(obj->base, (uint8_t *)data, chunk,
1235                         _cyhal_qspi_convert_bus_width(command->data.bus_width), &obj->context);
1236                     #else
1237                     status = (cy_rslt_t)Cy_SMIF_ReceiveDataBlocking_Ext(obj->base, (uint8_t *)data, chunk,
1238                         _cyhal_qspi_convert_bus_width(command->data.bus_width),
1239                         (cy_en_smif_data_rate_t)command->data.data_rate, &obj->context);
1240                     #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
1241                     if (CY_RSLT_SUCCESS != status)
1242                     {
1243                         break;
1244                     }
1245                 }
1246             }
1247         }
1248         read_bytes -= chunk;
1249         address += chunk;
1250         data = (uint8_t *)data + chunk;
1251     }
1252 
1253     return status;
1254 }
1255 
cyhal_qspi_read_async(cyhal_qspi_t * obj,const cyhal_qspi_command_t * command,uint32_t address,void * data,size_t * length)1256 cy_rslt_t cyhal_qspi_read_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, void *data, size_t *length)
1257 {
1258     #if CYHAL_DRIVER_AVAILABLE_SYSPM
1259     if (obj->pm_transition_pending)
1260     {
1261         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1262     }
1263     #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1264 
1265     cy_rslt_t status = _cyhal_qspi_command_transfer(obj, command, address, false);
1266 
1267     if (CY_RSLT_SUCCESS == status)
1268     {
1269         if (command->dummy_cycles.dummy_count > 0u)
1270         {
1271             status = _cyhal_qspi_wait_for_cmd_fifo(obj);
1272             if (CY_RSLT_SUCCESS == status)
1273             {
1274                 #if (CY_IP_MXSMIF_VERSION < 3)
1275                 status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_cycles.dummy_count);
1276                 #else
1277                 status = (cy_rslt_t)Cy_SMIF_SendDummyCycles_Ext(obj->base,
1278                         _cyhal_qspi_convert_bus_width(command->dummy_cycles.bus_width),
1279                         (cy_en_smif_data_rate_t)command->dummy_cycles.data_rate, command->dummy_cycles.dummy_count);
1280                 #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
1281             }
1282         }
1283 
1284         if (CY_RSLT_SUCCESS == status)
1285         {
1286             status = _cyhal_qspi_wait_for_cmd_fifo(obj);
1287             if (CY_RSLT_SUCCESS == status)
1288             {
1289                 #if (CY_IP_MXSMIF_VERSION < 3)
1290                 status = (cy_rslt_t)Cy_SMIF_ReceiveData(obj->base, (uint8_t *)data, (uint32_t)*length,
1291                     _cyhal_qspi_convert_bus_width(command->data.bus_width), _cyhal_qspi_cb_wrapper, &obj->context);
1292                 #else
1293                 status = (cy_rslt_t)Cy_SMIF_ReceiveData_Ext(obj->base, (uint8_t *)data, (uint32_t)*length,
1294                     _cyhal_qspi_convert_bus_width(command->data.bus_width),
1295                     (cy_en_smif_data_rate_t)command->data.data_rate, _cyhal_qspi_cb_wrapper, &obj->context);
1296                 #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
1297             }
1298         }
1299     }
1300     return status;
1301 }
1302 
1303 /* length can be up to 65536. */
cyhal_qspi_write(cyhal_qspi_t * obj,const cyhal_qspi_command_t * command,uint32_t address,const void * data,size_t * length)1304 cy_rslt_t cyhal_qspi_write(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, const void *data,
1305         size_t *length)
1306 {
1307     #if CYHAL_DRIVER_AVAILABLE_SYSPM
1308     if (obj->pm_transition_pending)
1309     {
1310         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1311     }
1312     #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1313     cy_rslt_t status = _cyhal_qspi_command_transfer(obj, command, address, false);
1314 
1315     if (CY_RSLT_SUCCESS == status)
1316     {
1317         if (command->dummy_cycles.dummy_count > 0u)
1318         {
1319             status = _cyhal_qspi_wait_for_cmd_fifo(obj);
1320             if (CY_RSLT_SUCCESS == status)
1321             {
1322                 #if (CY_IP_MXSMIF_VERSION < 3)
1323                 status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_cycles.dummy_count);
1324                 #else
1325                 status = (cy_rslt_t)Cy_SMIF_SendDummyCycles_Ext(obj->base,
1326                         _cyhal_qspi_convert_bus_width(command->dummy_cycles.bus_width),
1327                         (cy_en_smif_data_rate_t)command->dummy_cycles.data_rate, command->dummy_cycles.dummy_count);
1328                 #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
1329             }
1330         }
1331 
1332         if ((CY_SMIF_SUCCESS == status) && (*length > 0))
1333         {
1334             status = _cyhal_qspi_wait_for_cmd_fifo(obj);
1335             if (CY_RSLT_SUCCESS == status)
1336             {
1337                 #if (CY_IP_MXSMIF_VERSION < 3)
1338                 status = (cy_rslt_t)Cy_SMIF_TransmitDataBlocking(obj->base, (uint8_t *)data, *length,
1339                     _cyhal_qspi_convert_bus_width(command->data.bus_width), &obj->context);
1340                 #else
1341                 status = (cy_rslt_t)Cy_SMIF_TransmitDataBlocking_Ext(obj->base, (uint8_t *)data, *length,
1342                     _cyhal_qspi_convert_bus_width(command->data.bus_width),
1343                     (cy_en_smif_data_rate_t)command->data.data_rate, &obj->context);
1344                 #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
1345             }
1346         }
1347     }
1348 
1349     return status;
1350 }
1351 
1352 /* length can be up to 65536. */
cyhal_qspi_write_async(cyhal_qspi_t * obj,const cyhal_qspi_command_t * command,uint32_t address,const void * data,size_t * length)1353 cy_rslt_t cyhal_qspi_write_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, const void *data, size_t *length)
1354 {
1355     #if CYHAL_DRIVER_AVAILABLE_SYSPM
1356     if (obj->pm_transition_pending)
1357     {
1358         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1359     }
1360     #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1361 
1362     cy_rslt_t status = _cyhal_qspi_command_transfer(obj, command, address, false);
1363 
1364     if (CY_RSLT_SUCCESS == status)
1365     {
1366         if (command->dummy_cycles.dummy_count > 0u)
1367         {
1368             status = _cyhal_qspi_wait_for_cmd_fifo(obj);
1369             if (CY_RSLT_SUCCESS == status)
1370             {
1371                 #if (CY_IP_MXSMIF_VERSION < 3)
1372                 status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_cycles.dummy_count);
1373                 #else
1374                 status = (cy_rslt_t)Cy_SMIF_SendDummyCycles_Ext(obj->base,
1375                         _cyhal_qspi_convert_bus_width(command->dummy_cycles.bus_width),
1376                         (cy_en_smif_data_rate_t)command->dummy_cycles.data_rate, command->dummy_cycles.dummy_count);
1377                 #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
1378             }
1379         }
1380 
1381         if ((CY_SMIF_SUCCESS == status) && (*length > 0))
1382         {
1383             status = _cyhal_qspi_wait_for_cmd_fifo(obj);
1384             if (CY_RSLT_SUCCESS == status)
1385             {
1386                 #if (CY_IP_MXSMIF_VERSION < 3)
1387                 status = (cy_rslt_t)Cy_SMIF_TransmitData(obj->base, (uint8_t *)data, *length,
1388                     _cyhal_qspi_convert_bus_width(command->data.bus_width), _cyhal_qspi_cb_wrapper, &obj->context);
1389                 #else
1390                 status = (cy_rslt_t)Cy_SMIF_TransmitData_Ext(obj->base, (uint8_t *)data, *length,
1391                     _cyhal_qspi_convert_bus_width(command->data.bus_width),
1392                     (cy_en_smif_data_rate_t)command->data.data_rate, _cyhal_qspi_cb_wrapper, &obj->context);
1393                 #endif /* CY_IP_MXSMIF_VERSION < 3 or other */
1394             }
1395         }
1396     }
1397     return status;
1398 }
1399 
cyhal_qspi_transfer(cyhal_qspi_t * obj,const cyhal_qspi_command_t * command,uint32_t address,const void * tx_data,size_t tx_size,void * rx_data,size_t rx_size)1400 cy_rslt_t cyhal_qspi_transfer(
1401     cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, const void *tx_data, size_t tx_size, void *rx_data,
1402     size_t rx_size)
1403 {
1404     #if CYHAL_DRIVER_AVAILABLE_SYSPM
1405     if (obj->pm_transition_pending)
1406     {
1407         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1408     }
1409     #endif // CYHAL_DRIVER_AVAILABLE_SYSPM
1410 
1411     cy_rslt_t status = CY_RSLT_SUCCESS;
1412 
1413     if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0))
1414     {
1415         /* only command, no rx or tx */
1416         status = _cyhal_qspi_command_transfer(obj, command, address, true);
1417     }
1418     else
1419     {
1420         if (tx_data != NULL && tx_size)
1421         {
1422             status = cyhal_qspi_write(obj, command, address, tx_data, &tx_size);
1423         }
1424 
1425         if (status == CY_RSLT_SUCCESS)
1426         {
1427             if (rx_data != NULL && rx_size)
1428             {
1429                 status = cyhal_qspi_read(obj, command, address, rx_data, &rx_size);
1430             }
1431         }
1432     }
1433     return status;
1434 }
1435 
cyhal_qspi_register_callback(cyhal_qspi_t * obj,cyhal_qspi_event_callback_t callback,void * callback_arg)1436 void cyhal_qspi_register_callback(cyhal_qspi_t *obj, cyhal_qspi_event_callback_t callback, void *callback_arg)
1437 {
1438     uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
1439     obj->callback_data.callback = (cy_israddress) callback;
1440     obj->callback_data.callback_arg = callback_arg;
1441     cyhal_system_critical_section_exit(savedIntrStatus);
1442 
1443     obj->irq_cause = CYHAL_QSPI_EVENT_NONE;
1444 }
1445 
cyhal_qspi_enable_event(cyhal_qspi_t * obj,cyhal_qspi_event_t event,uint8_t intr_priority,bool enable)1446 void cyhal_qspi_enable_event(cyhal_qspi_t *obj, cyhal_qspi_event_t event, uint8_t intr_priority, bool enable)
1447 {
1448     if (enable)
1449     {
1450         obj->irq_cause |= event;
1451     }
1452     else
1453     {
1454         obj->irq_cause &= ~event;
1455     }
1456 
1457     _cyhal_system_irq_t irqn = _cyhal_qspi_irq_n[obj->resource.block_num];
1458     _cyhal_irq_set_priority(irqn, intr_priority);
1459 }
1460 
1461 #if defined(__cplusplus)
1462 }
1463 #endif /* __cplusplus */
1464 
1465 #endif /* CYHAL_DRIVER_AVAILABLE_QSPI */
1466