1 /*
2  * Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  *    contributors may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef NRFX_QSPI_H__
33 #define NRFX_QSPI_H__
34 
35 #include <nrfx.h>
36 #include <hal/nrf_qspi.h>
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 /**
43  * @defgroup nrfx_qspi QSPI driver
44  * @{
45  * @ingroup nrf_qspi
46  * @brief   Quad Serial Peripheral Interface (QSPI) peripheral driver.
47  */
48 
49 /** @brief QSPI driver instance configuration structure. */
50 typedef struct
51 {
52     uint32_t             xip_offset;   /**< Address offset into the external memory for Execute in Place operation. */
53     nrf_qspi_pins_t      pins;         /**< Pin configuration structure. */
54     nrf_qspi_prot_conf_t prot_if;      /**< Protocol layer interface configuration structure. */
55     nrf_qspi_phy_conf_t  phy_if;       /**< Physical layer interface configuration structure. */
56     uint8_t              irq_priority; /**< Interrupt priority. */
57 } nrfx_qspi_config_t;
58 
59 /**
60  * @brief QSPI instance default configuration.
61  *
62  * This configuration sets up QSPI with the following options:
63  * - no offset for address in the external memory for Execute in Place operation
64  * - single data line
65  * - FAST_READ opcode for reading
66  * - PP opcode for writing
67  * - 24 bit addressing mode
68  * - Deep Power-down disabled
69  * - clock frequency: 2 MHz for nRF52 Series, 6 MHz for nRF53 Series
70  * - SCK delay 5 clock ticks
71  * - mode 0 (data captured on the clock rising edge and transmitted on a falling edge. Clock base level is '0')
72  *
73  * @param[in] _pin_sck Pin for clock signal.
74  * @param[in] _pin_csn Pin for chip select signal.
75  * @param[in] _pin_io0 Pin 0 for I/O data.
76  * @param[in] _pin_io1 Pin 1 for I/O data.
77  * @param[in] _pin_io2 Pin 2 for I/O data.
78  * @param[in] _pin_io3 Pin 3 for I/O data.
79  */
80 #define NRFX_QSPI_DEFAULT_CONFIG(_pin_sck, _pin_csn, _pin_io0,         \
81                                  _pin_io1, _pin_io2, _pin_io3)         \
82 {                                                                      \
83     .xip_offset    = 0,                                                \
84     .pins = {                                                          \
85        .sck_pin    = _pin_sck,                                         \
86        .csn_pin    = _pin_csn,                                         \
87        .io0_pin    = _pin_io0,                                         \
88        .io1_pin    = _pin_io1,                                         \
89        .io2_pin    = _pin_io2,                                         \
90        .io3_pin    = _pin_io3                                          \
91     },                                                                 \
92     .prot_if = {                                                       \
93         .readoc    = NRF_QSPI_READOC_FASTREAD,                         \
94         .writeoc   = NRF_QSPI_WRITEOC_PP,                              \
95         .addrmode  = NRF_QSPI_ADDRMODE_24BIT,                          \
96         .dpmconfig = false,                                            \
97     },                                                                 \
98     .phy_if = {                                                        \
99         .sck_delay = 0x05,                                             \
100         .dpmen     = false,                                            \
101         .spi_mode  = NRF_QSPI_MODE_0,                                  \
102         .sck_freq  = NRF_QSPI_FREQ_DIV16,                              \
103     },                                                                 \
104     .irq_priority  = (uint8_t)NRFX_QSPI_DEFAULT_CONFIG_IRQ_PRIORITY,   \
105 }
106 
107 /** @brief QSPI custom instruction helper with the default configuration. */
108 #define NRFX_QSPI_DEFAULT_CINSTR(opc, len) \
109 {                                          \
110     .opcode    = (opc),                    \
111     .length    = (len),                    \
112     .io2_level = false,                    \
113     .io3_level = false,                    \
114     .wipwait   = false,                    \
115     .wren      = false                     \
116 }
117 
118 /**
119  * @brief QSPI master driver event types, passed to the handler routine provided
120  *        during initialization.
121  */
122 typedef enum
123 {
124     NRFX_QSPI_EVENT_DONE, /**< Transfer done. */
125 } nrfx_qspi_evt_t;
126 
127 /** @brief QSPI driver event handler type. */
128 typedef void (*nrfx_qspi_handler_t)(nrfx_qspi_evt_t event, void * p_context);
129 
130 /**
131  * @brief Function for initializing the QSPI driver instance.
132  *
133  * This function configures the peripheral and its interrupts, and activates it. During the
134  * activation process, the internal clocks are started and the QSPI peripheral tries to read
135  * the status byte to read the busy bit. Reading the status byte is done in a simple poll and wait
136  * mechanism.
137  * If the busy bit is 1, this indicates issues with the external memory device. As a result,
138  * @ref nrfx_qspi_init returns NRFX_ERROR_TIMEOUT.
139  *
140  * In case of issues:
141  * - Check the connection.
142  * - Make sure that the memory device does not perform other operations like erasing or writing.
143  * - Check if there is a short circuit.
144  *
145  * @param[in] p_config  Pointer to the structure with the initial configuration.
146  * @param[in] handler   Event handler provided by the user. If NULL, transfers
147  *                      will be performed in blocking mode.
148  * @param[in] p_context Pointer to context. Use in the interrupt handler.
149  *
150  * @retval NRFX_SUCCESS             Initialization was successful.
151  * @retval NRFX_ERROR_TIMEOUT       The peripheral cannot connect with external memory.
152  * @retval NRFX_ERROR_INVALID_STATE The driver was already initialized.
153  * @retval NRFX_ERROR_INVALID_PARAM The pin configuration was incorrect.
154  */
155 nrfx_err_t nrfx_qspi_init(nrfx_qspi_config_t const * p_config,
156                           nrfx_qspi_handler_t        handler,
157                           void *                     p_context);
158 
159 /** @brief Function for uninitializing the QSPI driver instance. */
160 void nrfx_qspi_uninit(void);
161 
162 /**
163  * @brief Function for reading data from the QSPI memory.
164  *
165  * Write, read, and erase operations check memory device busy state before starting the operation.
166  * If the memory is busy, the resulting action depends on the mode in which the read operation is used:
167  *  - blocking mode (without handler) - a delay occurs until the last operation runs and
168  *    until the operation data is being read.
169  *  - interrupt mode (with handler) - event emission occurs after the last operation
170  *    and reading of data are finished.
171  *
172  * @param[out] p_rx_buffer      Pointer to the receive buffer.
173  * @param[in]  rx_buffer_length Size of the data to read.
174  * @param[in]  src_address      Address in memory to read from.
175  *
176  * @retval NRFX_SUCCESS            The operation was successful (blocking mode) or operation
177  *                                 was commissioned (handler mode).
178  * @retval NRFX_ERROR_BUSY         The driver currently handles another operation.
179  * @retval NRFX_ERROR_INVALID_ADDR The provided buffer is not placed in the Data RAM region
180  *                                 or its address is not aligned to a 32-bit word.
181  */
182 nrfx_err_t nrfx_qspi_read(void *   p_rx_buffer,
183                           size_t   rx_buffer_length,
184                           uint32_t src_address);
185 
186 /**
187  * @brief Function for writing data to QSPI memory.
188  *
189  * Write, read, and erase operations check memory device busy state before starting the operation.
190  * If the memory is busy, the resulting action depends on the mode in which the write operation is used:
191  *  - blocking mode (without handler) - a delay occurs until the last operation runs or
192  *    until the operation data is being sent.
193  *  - interrupt mode (with handler) - event emission occurs after the last operation
194  *    and sending of operation data are finished.
195  * To manually control operation execution in the memory device, use @ref nrfx_qspi_mem_busy_check
196  * after executing the write function.
197  * Remember that an incoming event signalizes only that data was sent to the memory device and the periheral
198  * before the write operation checked if memory was busy.
199  *
200  * @param[in] p_tx_buffer      Pointer to the writing buffer.
201  * @param[in] tx_buffer_length Size of the data to write.
202  * @param[in] dst_address      Address in memory to write to.
203  *
204  * @retval NRFX_SUCCESS            The operation was successful (blocking mode) or operation
205  *                                 was commissioned (handler mode).
206  * @retval NRFX_ERROR_BUSY         The driver currently handles other operation.
207  * @retval NRFX_ERROR_INVALID_ADDR The provided buffer is not placed in the Data RAM region
208  *                                 or its address is not aligned to a 32-bit word.
209  */
210 nrfx_err_t nrfx_qspi_write(void const * p_tx_buffer,
211                            size_t       tx_buffer_length,
212                            uint32_t     dst_address);
213 
214 /**
215  * @brief Function for starting erasing of one memory block - 4KB, 64KB, or the whole chip.
216  *
217  * Write, read, and erase operations check memory device busy state before starting the operation.
218  * If the memory is busy, the resulting action depends on the mode in which the erase operation is used:
219  *  - blocking mode (without handler) - a delay occurs until the last operation runs or
220  *    until the operation data is being sent.
221  *  - interrupt mode (with handler) - event emission occurs after the last operation
222  *    and sending of operation data are finished.
223  * To manually control operation execution in the memory device, use @ref nrfx_qspi_mem_busy_check
224  * after executing the erase function.
225  * Remember that an incoming event signalizes only that data was sent to the memory device and the periheral
226  * before the erase operation checked if memory was busy.
227  *
228  * @param[in] length        Size of data to erase. See @ref nrf_qspi_erase_len_t.
229  * @param[in] start_address Memory address to start erasing. If chip erase is performed, address
230  *                          field is ommited.
231  *
232  * @retval NRFX_SUCCESS            The operation was successful (blocking mode) or operation
233  *                                 was commissioned (handler mode).
234  * @retval NRFX_ERROR_INVALID_ADDR The provided start address is not aligned to a 32-bit word.
235  * @retval NRFX_ERROR_BUSY         The driver currently handles another operation.
236  */
237 nrfx_err_t nrfx_qspi_erase(nrf_qspi_erase_len_t length,
238                            uint32_t             start_address);
239 
240 /**
241  * @brief Function for starting an erase operation of the whole chip.
242  *
243  * @retval NRFX_SUCCESS    The operation was successful (blocking mode) or operation
244  *                         was commissioned (handler mode).
245  * @retval NRFX_ERROR_BUSY The driver currently handles another operation.
246  */
247 nrfx_err_t nrfx_qspi_chip_erase(void);
248 
249 /**
250  * @brief Function for getting the current driver status and status byte of memory device with
251  *        testing WIP (write in progress) bit.
252  *
253  * @retval NRFX_SUCCESS    The driver and memory are ready to handle a new operation.
254  * @retval NRFX_ERROR_BUSY The driver or memory currently handle another operation.
255  */
256 nrfx_err_t nrfx_qspi_mem_busy_check(void);
257 
258 /**
259  * @brief Function for sending operation code, sending data, and receiving data from the memory device.
260  *
261  * Use this function to transfer configuration data to memory and to receive data from memory.
262  * Pointers can be addresses from flash memory.
263  * This function is a synchronous function and should be used only if necessary.
264  *
265  * @param[in]  p_config    Pointer to the structure with opcode and transfer configuration.
266  * @param[in]  p_tx_buffer Pointer to the array with data to send. Can be NULL if only opcode is transmitted.
267  * @param[out] p_rx_buffer Pointer to the array for data to receive. Can be NULL if there is nothing to receive.
268  *
269  * @retval NRFX_SUCCESS       The operation was successful.
270  * @retval NRFX_ERROR_TIMEOUT The external memory is busy or there are connection issues.
271  * @retval NRFX_ERROR_BUSY    The driver currently handles other operation.
272  */
273 nrfx_err_t nrfx_qspi_cinstr_xfer(nrf_qspi_cinstr_conf_t const * p_config,
274                                  void const *                   p_tx_buffer,
275                                  void *                         p_rx_buffer);
276 
277 /**
278  * @brief Function for sending operation code and data to the memory device with simpler configuration.
279  *
280  * Use this function to transfer configuration data to memory and to receive data from memory.
281  * This function is a synchronous function and should be used only if necessary.
282  *
283  * @param[in] opcode      Operation code. Sending first.
284  * @param[in] length      Length of the data to send and opcode. See @ref nrf_qspi_cinstr_len_t.
285  * @param[in] p_tx_buffer Pointer to input data array.
286  *
287  * @retval NRFX_SUCCESS    The operation was successful.
288  * @retval NRFX_ERROR_BUSY The driver currently handles another operation.
289  */
290 nrfx_err_t nrfx_qspi_cinstr_quick_send(uint8_t               opcode,
291                                        nrf_qspi_cinstr_len_t length,
292                                        void const *          p_tx_buffer);
293 
294 /**
295  * @brief Function for starting the custom instruction long frame mode.
296  *
297  * The long frame mode is a mechanism that allows for arbitrary byte length custom instructions.
298  * Use this function to initiate a custom transaction by sending custom instruction opcode.
299  * To send and receive data, use @ref nrfx_qspi_lfm_xfer.
300  *
301  * @param[in] p_config Pointer to the structure with custom instruction opcode and transfer
302  *                     configuration. Transfer length must be set to @ref NRF_QSPI_CINSTR_LEN_1B.
303  *
304  * @retval NRFX_SUCCESS       Operation was successful.
305  * @retval NRFX_ERROR_BUSY    Driver currently handles other operation.
306  * @retval NRFX_ERROR_TIMEOUT External memory is busy or there are connection issues.
307  */
308 nrfx_err_t nrfx_qspi_lfm_start(nrf_qspi_cinstr_conf_t const * p_config);
309 
310 /**
311  * @brief Function for sending and receiving data in the custom instruction long frame mode.
312  *
313  * Both specified buffers must be at least @p transfer_length bytes in size.
314  *
315  * @param[in]  p_tx_buffer     Pointer to the array with data to send.
316  *                             Can be NULL if there is nothing to send.
317  * @param[out] p_rx_buffer     Pointer to the array for receiving data.
318  *                             Can be NULL if there is nothing to receive.
319  * @param[in]  transfer_length Number of bytes to send and receive.
320  * @param[in]  finalize        True if custom instruction long frame mode is to be finalized
321  *                             after this transfer.
322  *
323  * @retval NRFX_SUCCESS       Operation was successful.
324  * @retval NRFX_ERROR_TIMEOUT External memory is busy or there are connection issues.
325  *                            Long frame mode becomes deactivated.
326  */
327 nrfx_err_t nrfx_qspi_lfm_xfer(void const * p_tx_buffer,
328                               void *       p_rx_buffer,
329                               size_t       transfer_length,
330                               bool         finalize);
331 
332 #if NRF_QSPI_HAS_XIP_ENC
333 /**
334  * @brief Function for setting the XIP encryption.
335  *
336  * @param[in] p_config XIP encryption configuration structure.
337  *                     To disable encryption, pass NULL pointer as argument.
338  *
339  * @retval NRFX_SUCCESS    Operation was successful.
340  * @retval NRFX_ERROR_BUSY Driver currently handles other operation.
341  */
342 nrfx_err_t nrfx_qspi_xip_encrypt(nrf_qspi_encryption_t const * p_config);
343 #endif
344 
345 #if NRF_QSPI_HAS_DMA_ENC
346 /**
347  * @brief Function for setting the EasyDMA encryption.
348  *
349  * @param[in] p_config DMA encryption configuration structure.
350  *                     To disable encryption, pass NULL pointer as argument.
351  *
352  * @retval NRFX_SUCCESS    Operation was successful.
353  * @retval NRFX_ERROR_BUSY Driver currently handles other operation.
354  */
355 nrfx_err_t nrfx_qspi_dma_encrypt(nrf_qspi_encryption_t const * p_config);
356 #endif
357 
358 /** @} */
359 
360 
361 void nrfx_qspi_irq_handler(void);
362 
363 
364 #ifdef __cplusplus
365 }
366 #endif
367 
368 #endif // NRFX_QSPI_H__
369