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