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 #include <nrfx.h>
33
34 #if NRFX_CHECK(NRFX_QSPI_ENABLED)
35
36 #include <nrfx_qspi.h>
37
38 /** @brief Command byte used to read status register. */
39 #define QSPI_STD_CMD_RDSR 0x05
40
41 /** @brief Byte used to mask status register and retrieve the write-in-progess bit. */
42 #define QSPI_MEM_STATUSREG_WIP_Pos 0x01
43
44 /** @brief Default time used in timeout function. */
45 #define QSPI_DEF_WAIT_TIME_US 10
46
47 /** @brief Default number of tries in timeout function. */
48 #define QSPI_DEF_WAIT_ATTEMPTS 100
49
50 /** @brief Control block - driver instance local data. */
51 typedef struct
52 {
53 nrfx_qspi_handler_t handler; /**< Handler. */
54 nrfx_drv_state_t state; /**< Driver state. */
55 volatile bool is_busy; /**< Flag indicating that an operation is currently being performed. */
56 void * p_context; /**< Driver context used in interrupt. */
57 } qspi_control_block_t;
58
59 static qspi_control_block_t m_cb;
60
qspi_task_perform(nrf_qspi_task_t task)61 static nrfx_err_t qspi_task_perform(nrf_qspi_task_t task)
62 {
63 // Wait for peripheral
64 if (m_cb.is_busy)
65 {
66 return NRFX_ERROR_BUSY;
67 }
68
69 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
70
71 if (m_cb.handler)
72 {
73 m_cb.is_busy = true;
74 nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
75 }
76
77 nrf_qspi_task_trigger(NRF_QSPI, task);
78
79 if (m_cb.handler == NULL)
80 {
81 while (!nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY))
82 {};
83 }
84 return NRFX_SUCCESS;
85 }
86
qspi_pins_configure(nrf_qspi_pins_t const * p_config)87 static bool qspi_pins_configure(nrf_qspi_pins_t const * p_config)
88 {
89 // Check if the user set meaningful values to struct fields. If not, return false.
90 if ((p_config->sck_pin == NRF_QSPI_PIN_NOT_CONNECTED) ||
91 (p_config->csn_pin == NRF_QSPI_PIN_NOT_CONNECTED) ||
92 (p_config->io0_pin == NRF_QSPI_PIN_NOT_CONNECTED) ||
93 (p_config->io1_pin == NRF_QSPI_PIN_NOT_CONNECTED))
94 {
95 return false;
96 }
97
98 nrf_qspi_pins_set(NRF_QSPI, p_config);
99
100 return true;
101 }
102
qspi_ready_wait(void)103 static nrfx_err_t qspi_ready_wait(void)
104 {
105 bool result;
106 NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY),
107 QSPI_DEF_WAIT_ATTEMPTS,
108 QSPI_DEF_WAIT_TIME_US,
109 result);
110 if (!result)
111 {
112 return NRFX_ERROR_TIMEOUT;
113 }
114
115 return NRFX_SUCCESS;
116 }
117
nrfx_qspi_init(nrfx_qspi_config_t const * p_config,nrfx_qspi_handler_t handler,void * p_context)118 nrfx_err_t nrfx_qspi_init(nrfx_qspi_config_t const * p_config,
119 nrfx_qspi_handler_t handler,
120 void * p_context)
121 {
122 NRFX_ASSERT(p_config);
123 if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
124 {
125 return NRFX_ERROR_INVALID_STATE;
126 }
127
128 if (!qspi_pins_configure(&p_config->pins))
129 {
130 return NRFX_ERROR_INVALID_PARAM;
131 }
132
133 nrf_qspi_xip_offset_set(NRF_QSPI, p_config->xip_offset);
134 nrf_qspi_ifconfig0_set(NRF_QSPI, &p_config->prot_if);
135 nrf_qspi_ifconfig1_set(NRF_QSPI, &p_config->phy_if);
136
137 m_cb.is_busy = false;
138 m_cb.handler = handler;
139 m_cb.p_context = p_context;
140
141 /* QSPI interrupt is disabled because the device should be enabled in polling mode (wait for activate
142 task event ready)*/
143 nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
144
145 if (handler)
146 {
147 NRFX_IRQ_PRIORITY_SET(QSPI_IRQn, p_config->irq_priority);
148 NRFX_IRQ_ENABLE(QSPI_IRQn);
149 }
150
151 m_cb.state = NRFX_DRV_STATE_INITIALIZED;
152
153 nrf_qspi_enable(NRF_QSPI);
154
155 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
156 nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_ACTIVATE);
157
158 // Waiting for the peripheral to activate
159
160 return qspi_ready_wait();
161 }
162
nrfx_qspi_cinstr_xfer(nrf_qspi_cinstr_conf_t const * p_config,void const * p_tx_buffer,void * p_rx_buffer)163 nrfx_err_t nrfx_qspi_cinstr_xfer(nrf_qspi_cinstr_conf_t const * p_config,
164 void const * p_tx_buffer,
165 void * p_rx_buffer)
166 {
167 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
168
169 if (m_cb.is_busy)
170 {
171 return NRFX_ERROR_BUSY;
172 }
173
174 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
175 /* In some cases, only opcode should be sent. To prevent execution, set function code is
176 * surrounded by an if.
177 */
178 if (p_tx_buffer)
179 {
180 nrf_qspi_cinstrdata_set(NRF_QSPI, p_config->length, p_tx_buffer);
181 }
182
183 nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
184
185 nrf_qspi_cinstr_transfer_start(NRF_QSPI, p_config);
186
187 if (qspi_ready_wait() == NRFX_ERROR_TIMEOUT)
188 {
189 // This timeout should never occur when WIPWAIT is not active, since in this
190 // case the QSPI peripheral should send the command immediately, without any
191 // waiting for previous write to complete.
192 NRFX_ASSERT(p_config->wipwait);
193
194 return NRFX_ERROR_TIMEOUT;
195 }
196 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
197
198 if (p_rx_buffer)
199 {
200 nrf_qspi_cinstrdata_get(NRF_QSPI, p_config->length, p_rx_buffer);
201 }
202
203 return NRFX_SUCCESS;
204 }
205
nrfx_qspi_cinstr_quick_send(uint8_t opcode,nrf_qspi_cinstr_len_t length,void const * p_tx_buffer)206 nrfx_err_t nrfx_qspi_cinstr_quick_send(uint8_t opcode,
207 nrf_qspi_cinstr_len_t length,
208 void const * p_tx_buffer)
209 {
210 nrf_qspi_cinstr_conf_t config = NRFX_QSPI_DEFAULT_CINSTR(opcode, length);
211 return nrfx_qspi_cinstr_xfer(&config, p_tx_buffer, NULL);
212 }
213
nrfx_qspi_lfm_start(nrf_qspi_cinstr_conf_t const * p_config)214 nrfx_err_t nrfx_qspi_lfm_start(nrf_qspi_cinstr_conf_t const * p_config)
215 {
216 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
217 NRFX_ASSERT(!(nrf_qspi_cinstr_long_transfer_is_ongoing(NRF_QSPI)));
218 NRFX_ASSERT(p_config->length == NRF_QSPI_CINSTR_LEN_1B);
219
220 if (m_cb.is_busy)
221 {
222 return NRFX_ERROR_BUSY;
223 }
224
225 nrf_qspi_cinstr_long_transfer_start(NRF_QSPI, p_config);
226
227 if (qspi_ready_wait() == NRFX_ERROR_TIMEOUT)
228 {
229 /* In case of error, abort long frame mode */
230 nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, NRF_QSPI_CINSTR_LEN_1B, true);
231 return NRFX_ERROR_TIMEOUT;
232 }
233
234 m_cb.is_busy = true;
235 return NRFX_SUCCESS;
236 }
237
nrfx_qspi_lfm_xfer(void const * p_tx_buffer,void * p_rx_buffer,size_t transfer_length,bool finalize)238 nrfx_err_t nrfx_qspi_lfm_xfer(void const * p_tx_buffer,
239 void * p_rx_buffer,
240 size_t transfer_length,
241 bool finalize)
242 {
243 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
244 NRFX_ASSERT(nrf_qspi_cinstr_long_transfer_is_ongoing(NRF_QSPI));
245
246 nrfx_err_t status = NRFX_SUCCESS;
247
248 /* Perform transfers in packets of 8 bytes. Last transfer may be shorter. */
249 nrf_qspi_cinstr_len_t length = NRF_QSPI_CINSTR_LEN_9B;
250 for (uint32_t curr_byte = 0; curr_byte < transfer_length; curr_byte += 8)
251 {
252 uint32_t remaining_bytes = transfer_length - curr_byte;
253 if (remaining_bytes < 8)
254 {
255 length = (nrf_qspi_cinstr_len_t)(remaining_bytes + 1);
256 }
257
258 if (p_tx_buffer)
259 {
260 nrf_qspi_cinstrdata_set(NRF_QSPI,
261 length,
262 &((uint8_t const *)p_tx_buffer)[curr_byte]);
263 }
264
265 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
266
267 if (remaining_bytes <= 8)
268 {
269 nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, length, finalize);
270 }
271 else
272 {
273 nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, length, false);
274 }
275
276 if (qspi_ready_wait() == NRFX_ERROR_TIMEOUT)
277 {
278 /* In case of error, abort long frame mode */
279 nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, NRF_QSPI_CINSTR_LEN_1B, true);
280 status = NRFX_ERROR_TIMEOUT;
281 break;
282 }
283
284 if (p_rx_buffer)
285 {
286 nrf_qspi_cinstrdata_get(NRF_QSPI,
287 length,
288 &((uint8_t *)p_rx_buffer)[curr_byte]);
289 }
290 }
291 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
292
293 if ((finalize) || (status == NRFX_ERROR_TIMEOUT))
294 {
295 m_cb.is_busy = false;
296 }
297
298 return status;
299 }
300
nrfx_qspi_mem_busy_check(void)301 nrfx_err_t nrfx_qspi_mem_busy_check(void)
302 {
303 nrfx_err_t ret_code;
304 uint8_t status_value = 0;
305
306 nrf_qspi_cinstr_conf_t const config =
307 NRFX_QSPI_DEFAULT_CINSTR(QSPI_STD_CMD_RDSR,
308 NRF_QSPI_CINSTR_LEN_2B);
309 ret_code = nrfx_qspi_cinstr_xfer(&config, &status_value, &status_value);
310
311 if (ret_code != NRFX_SUCCESS)
312 {
313 return ret_code;
314 }
315
316 if ((status_value & QSPI_MEM_STATUSREG_WIP_Pos) != 0x00)
317 {
318 return NRFX_ERROR_BUSY;
319 }
320
321 return NRFX_SUCCESS;
322 }
323
nrfx_qspi_uninit(void)324 void nrfx_qspi_uninit(void)
325 {
326 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
327
328 if (nrf_qspi_cinstr_long_transfer_is_ongoing(NRF_QSPI))
329 {
330 nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, NRF_QSPI_CINSTR_LEN_1B, true);
331 }
332
333 nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
334
335 nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_DEACTIVATE);
336
337 nrf_qspi_disable(NRF_QSPI);
338
339 NRFX_IRQ_DISABLE(QSPI_IRQn);
340
341 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
342
343 m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
344 }
345
nrfx_qspi_write(void const * p_tx_buffer,size_t tx_buffer_length,uint32_t dst_address)346 nrfx_err_t nrfx_qspi_write(void const * p_tx_buffer,
347 size_t tx_buffer_length,
348 uint32_t dst_address)
349 {
350 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
351 NRFX_ASSERT(p_tx_buffer != NULL);
352
353 if (!nrfx_is_in_ram(p_tx_buffer) || !nrfx_is_word_aligned(p_tx_buffer))
354 {
355 return NRFX_ERROR_INVALID_ADDR;
356 }
357
358 nrf_qspi_write_buffer_set(NRF_QSPI, p_tx_buffer, tx_buffer_length, dst_address);
359 return qspi_task_perform(NRF_QSPI_TASK_WRITESTART);
360 }
361
nrfx_qspi_read(void * p_rx_buffer,size_t rx_buffer_length,uint32_t src_address)362 nrfx_err_t nrfx_qspi_read(void * p_rx_buffer,
363 size_t rx_buffer_length,
364 uint32_t src_address)
365 {
366 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
367 NRFX_ASSERT(p_rx_buffer != NULL);
368
369 if (!nrfx_is_in_ram(p_rx_buffer) || !nrfx_is_word_aligned(p_rx_buffer))
370 {
371 return NRFX_ERROR_INVALID_ADDR;
372 }
373
374 nrf_qspi_read_buffer_set(NRF_QSPI, p_rx_buffer, rx_buffer_length, src_address);
375 return qspi_task_perform(NRF_QSPI_TASK_READSTART);
376 }
377
nrfx_qspi_erase(nrf_qspi_erase_len_t length,uint32_t start_address)378 nrfx_err_t nrfx_qspi_erase(nrf_qspi_erase_len_t length,
379 uint32_t start_address)
380 {
381 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
382
383 if (!nrfx_is_word_aligned((void const *)start_address))
384 {
385 return NRFX_ERROR_INVALID_ADDR;
386 }
387
388 nrf_qspi_erase_ptr_set(NRF_QSPI, start_address, length);
389 return qspi_task_perform(NRF_QSPI_TASK_ERASESTART);
390 }
391
nrfx_qspi_chip_erase(void)392 nrfx_err_t nrfx_qspi_chip_erase(void)
393 {
394 return nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_ALL, 0);
395 }
396
397 #if NRF_QSPI_HAS_XIP_ENC
nrfx_qspi_xip_encrypt(nrf_qspi_encryption_t const * p_config)398 nrfx_err_t nrfx_qspi_xip_encrypt(nrf_qspi_encryption_t const * p_config)
399 {
400 if (m_cb.is_busy)
401 {
402 return NRFX_ERROR_BUSY;
403 }
404
405 if (p_config)
406 {
407 nrf_qspi_xip_encryption_configure(NRF_QSPI, p_config);
408 nrf_qspi_xip_encryption_set(NRF_QSPI, true);
409 }
410 else
411 {
412 nrf_qspi_xip_encryption_set(NRF_QSPI, false);
413 }
414
415 return NRFX_SUCCESS;
416 }
417 #endif
418
419 #if NRF_QSPI_HAS_DMA_ENC
nrfx_qspi_dma_encrypt(nrf_qspi_encryption_t const * p_config)420 nrfx_err_t nrfx_qspi_dma_encrypt(nrf_qspi_encryption_t const * p_config)
421 {
422 if (m_cb.is_busy)
423 {
424 return NRFX_ERROR_BUSY;
425 }
426
427 if (p_config)
428 {
429 nrf_qspi_dma_encryption_configure(NRF_QSPI, p_config);
430 nrf_qspi_dma_encryption_set(NRF_QSPI, true);
431 }
432 else
433 {
434 nrf_qspi_dma_encryption_set(NRF_QSPI, false);
435 }
436
437 return NRFX_SUCCESS;
438 }
439 #endif
440
nrfx_qspi_irq_handler(void)441 void nrfx_qspi_irq_handler(void)
442 {
443 // Catch Event ready interrupts
444 if (nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY))
445 {
446 m_cb.is_busy = false;
447 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
448 m_cb.handler(NRFX_QSPI_EVENT_DONE, m_cb.p_context);
449 }
450 }
451
452 #endif // NRFX_CHECK(NRFX_QSPI_ENABLED)
453