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