1 /***********************************************************************************************//**
2  * \file cy_serial_flash_qspi.h
3  *
4  * \brief
5  * Provides APIs for interacting with an external flash connected to the SPI or
6  * QSPI interface. Read is implemented as both blocking and non-blocking whereas
7  * write, and erase are implemented as blocking functions.
8  *
9  ***************************************************************************************************
10  * \copyright
11  * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
12  * an affiliate of Cypress Semiconductor Corporation
13  *
14  * SPDX-License-Identifier: Apache-2.0
15  *
16  * Licensed under the Apache License, Version 2.0 (the "License");
17  * you may not use this file except in compliance with the License.
18  * You may obtain a copy of the License at
19  *
20  *     http://www.apache.org/licenses/LICENSE-2.0
21  *
22  * Unless required by applicable law or agreed to in writing, software
23  * distributed under the License is distributed on an "AS IS" BASIS,
24  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25  * See the License for the specific language governing permissions and
26  * limitations under the License.
27  **************************************************************************************************/
28 
29 /**
30  * \addtogroup group_board_libs Serial Flash
31  * \ingroup group_lib
32  * \{
33  *
34  * \section section_resource_usage DMA Resource Usage
35  * This library uses fixed DMA (Datawire or DW) resources and supports DMA only
36  * for the following devices. DMA is not supported for other devices and the
37  * functions \ref cy_serial_flash_qspi_read_async() and
38  * \ref cy_serial_flash_qspi_abort_read() will return
39  * \ref CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED error and
40  * \ref cy_serial_flash_qspi_set_dma_interrupt_priority() will simply return
41  * doing nothing.
42  * * CY8C6xx4, CY8C6xx5, CY8C6xx8, CY8C6xxA, CYB06xx5, CYB06xxA, CYS06xxA: <b>DW1, Channel 23</b>
43  * * CY8C6xx6, CY8C6xx7, CYB06xx7: <b>DW1, Channel 15</b>
44  */
45 
46 #pragma once
47 
48 #include <stddef.h>
49 #include "cy_result.h"
50 #include "cy_pdl.h"
51 #include "cyhal.h"
52 
53 #ifdef CY_IP_MXSMIF
54 
55 #if defined(__cplusplus)
56 extern "C" {
57 #endif
58 
59 /** The function or operation is not supported on the target or the memory */
60 #define CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED \
61     (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 1))
62 
63 /** Parameters passed to a function are invalid */
64 #define CY_RSLT_SERIAL_FLASH_ERR_BAD_PARAM \
65     (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 2))
66 
67 /** A previously initiated read operation is not yet complete */
68 #define CY_RSLT_SERIAL_FLASH_ERR_READ_BUSY \
69     (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 3))
70 
71 /** A DMA error occurred during read transfer */
72 #define CY_RSLT_SERIAL_FLASH_ERR_DMA \
73     (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 4))
74 
75 /** Read abort failed. QSPI block is busy. */
76 #define CY_RSLT_SERIAL_FLASH_ERR_QSPI_BUSY \
77     (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 5))
78 
79 #ifdef DOXYGEN
80 /** Enables thread-safety for use with multi-threaded RTOS environment. */
81 #define CY_SERIAL_FLASH_QSPI_THREAD_SAFE
82 #endif /* #ifdef DOXYGEN */
83 
84 /**
85  * Callback pointer to use with \ref cy_serial_flash_qspi_read_async().
86  * \param operation_status Status of the read operation
87  * \param callback_arg Pointer to be passed back to the callback function
88  */
89 typedef void (* cy_serial_flash_qspi_read_complete_callback_t)(cy_rslt_t operation_status,
90                                                                void* callback_arg);
91 
92 /**
93  * \brief Initializes the serial flash memory. This function accepts up to 8
94  * I/Os. Number of I/Os depend on the type of memory interface. Pass NC when an
95  * I/O is unused.
96  * Single SPI - (io0, io1) or (io2, io3) or (io4, io5) or (io6, io7)
97  * Dual SPI   - (io0, io1) or (io2, io3) or (io4, io5) or (io6, io7)
98  * Quad SPI   - (io0, io1, io2, io3) or (io4, io5, io6, io7)
99  * Octal SPI  - All 8 I/Os are used.
100  * \param mem_config Memory configuration to be used for initializing
101  * \param io0 Data/IO pin 0 connected to the memory, Pass NC when unused.
102  * \param io1 Data/IO pin 1 connected to the memory, Pass NC when unused.
103  * \param io2 Data/IO pin 2 connected to the memory, Pass NC when unused.
104  * \param io3 Data/IO pin 3 connected to the memory, Pass NC when unused.
105  * \param io4 Data/IO pin 4 connected to the memory, Pass NC when unused.
106  * \param io5 Data/IO pin 5 connected to the memory, Pass NC when unused.
107  * \param io6 Data/IO pin 6 connected to the memory, Pass NC when unused.
108  * \param io7 Data/IO pin 7 connected to the memory, Pass NC when unused.
109  * \param sclk Clock pin connected to the memory
110  * \param ssel Slave select pin connected to the memory
111  * \param hz Clock frequency to be used with the memory.
112  * \returns CY_RSLT_SUCCESS if the initialization was successful, an error code
113  *          otherwise.
114  */
115 cy_rslt_t cy_serial_flash_qspi_init(
116     const cy_stc_smif_mem_config_t* mem_config,
117     cyhal_gpio_t io0,
118     cyhal_gpio_t io1,
119     cyhal_gpio_t io2,
120     cyhal_gpio_t io3,
121     cyhal_gpio_t io4,
122     cyhal_gpio_t io5,
123     cyhal_gpio_t io6,
124     cyhal_gpio_t io7,
125     cyhal_gpio_t sclk,
126     cyhal_gpio_t ssel,
127     uint32_t hz);
128 
129 /**
130  * \brief De-initializes the serial flash memory.
131  * Before calling this function, ensure that an ongoing asynchronous read
132  * operation is either completed or successfully aborted.
133  * Async read is started by calling \ref cy_serial_flash_qspi_read_async() and
134  * aborted by calling \ref cy_serial_flash_qspi_abort_read().
135  */
136 void cy_serial_flash_qspi_deinit(void);
137 
138 /**
139  * \brief Returns the size of the serial flash memory in bytes.
140  * \returns Memory size in bytes.
141  */
142 size_t cy_serial_flash_qspi_get_size(void);
143 
144 /**
145  * \brief Returns the size of the erase sector to which the given address
146  * belongs. Address is used only for a memory with hybrid sector size.
147  * \param addr Address that belongs to the sector for which size is returned.
148  * \returns Erase sector size in bytes.
149  */
150 size_t cy_serial_flash_qspi_get_erase_size(uint32_t addr);
151 
152 /**
153  * \brief Returns the page size for programming of the sector to which the given
154  * address belongs. Address is used only for a memory with hybrid sector size.
155  * \param addr Address that belongs to the sector for which size is returned.
156  * \returns Page size in bytes.
157  */
158 size_t cy_serial_flash_qspi_get_prog_size(uint32_t addr);
159 
160 /**
161  * \brief Utility function to calculate the starting address of an erase sector
162  * to which the given address belongs.
163  * \param addr Address in the sector for which the starting address is returned.
164  * \returns Starting address of the sector
165  */
cy_serial_flash_get_sector_start_address(uint32_t addr)166 __STATIC_INLINE uint32_t cy_serial_flash_get_sector_start_address(uint32_t addr)
167 {
168     return (addr & ~(cy_serial_flash_qspi_get_erase_size(addr) - 1));
169 }
170 
171 
172 /**
173  * \brief Reads data from the serial flash memory. This is a blocking
174  * function. Returns error if (addr + length) exceeds the flash size.
175  * \param addr Starting address to read from
176  * \param length Number of data bytes to read
177  * \param buf Pointer to the buffer to store the data read from the memory
178  * \returns CY_RSLT_SUCCESS if the read was successful, an error code otherwise.
179  */
180 cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t* buf);
181 
182 /**
183  * \brief Reads data from the serial flash memory. This is a non-blocking
184  * function. Returns error if (addr + length) exceeds the flash size.
185  * Uses fixed DMA (DW) instance and channel for transferring the data from
186  * QSPI RX FIFO to the user-provided buffer.
187  * \param addr Starting address to read from
188  * \param length Number of data bytes to read
189  * \param buf Pointer to the buffer to store the data read from the memory
190  * \param callback Pointer to the callback function to be called after the read
191  *        operation is complete. Callback is invoked from the DMA ISR.
192  * \param callback_arg Pointer to the argument to be passed to the callback
193  *        function
194  * \returns CY_RSLT_SUCCESS if the read was successful, an error code otherwise.
195  */
196 cy_rslt_t cy_serial_flash_qspi_read_async(uint32_t addr, size_t length, uint8_t* buf,
197                                           cy_serial_flash_qspi_read_complete_callback_t callback,
198                                           void* callback_arg);
199 
200 /**
201  * \brief Aborts an ongoing asynchronous read initiated by calling
202  * \ref cy_serial_flash_qspi_read_async().
203  *
204  * \returns CY_RSLT_SUCCESS if the abort was successful, an error code
205  *          if the QSPI block is still busy after a timeout.
206  */
207 cy_rslt_t cy_serial_flash_qspi_abort_read(void);
208 
209 /**
210  * \brief Writes the data to the serial flash memory. The program area
211  * must have been erased prior to calling this API using
212  * \ref cy_serial_flash_qspi_erase() This is a blocking function. Returns error if
213  * (addr + length) exceeds the flash size.
214  * \param addr Starting address to write to
215  * \param length Number of bytes to write
216  * \param buf Pointer to the buffer storing the data to be written
217  * \returns CY_RSLT_SUCCESS if the write was successful, an error code
218  *          otherwise.
219  */
220 cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t* buf);
221 
222 /**
223  * \brief Erases the serial flash memory, uses chip erase command when
224  * addr = 0 and length = flash_size otherwise uses sector erase command. This is
225  * a blocking function. Returns error if addr or (addr + length) is not aligned
226  * to the sector size or if (addr + length) exceeds the flash size.
227  * For memories with hybrid sectors, returns error if the end address
228  * (=addr + length) is not aligned to the size of the sector in which the end
229  * address is located.
230  * Call \ref cy_serial_flash_qspi_get_size() to get the flash size and
231  * call \ref cy_serial_flash_qspi_get_erase_size() to get the size of an erase
232  * sector.
233  *
234  * \param addr Starting address to begin erasing
235  * \param length Number of bytes to erase
236  * \returns CY_RSLT_SUCCESS if the erase was successful, an error code
237  *          otherwise.
238  */
239 cy_rslt_t cy_serial_flash_qspi_erase(uint32_t addr, size_t length);
240 
241 /**
242  * \brief Enables Execute-in-Place (memory mapped) mode on the MCU. This
243  * function does not send any command to the serial flash. This may not be
244  * supported on all the targets in which case
245  * CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED is returned.
246  * \param enable true: XIP mode is set, false: normal mode is set
247  * \returns CY_RSLT_SUCCESS if the operation was successful.
248  *          CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED if the target does not
249  *          support XIP.
250  */
251 cy_rslt_t cy_serial_flash_qspi_enable_xip(bool enable);
252 
253 /**
254  * \brief Changes QSPI interrupt priority
255  * \param priority interrupt priority to be set
256  */
257 void cy_serial_flash_qspi_set_interrupt_priority(uint8_t priority);
258 
259 /**
260  * \brief Changes the DMA interrupt priority
261  * \param priority interrupt priority to be set
262  */
263 void cy_serial_flash_qspi_set_dma_interrupt_priority(uint8_t priority);
264 
265 
266 #if defined(__cplusplus)
267 }
268 #endif
269 
270 #endif // CY_IP_MXSMIF
271 
272 /** \} group_board_libs */
273