xref: /nrf52832-nimble/nordic/nrfx/drivers/src/nrfx_qspi.c (revision 150812a83cab50279bd772ef6db1bfaf255f2c5b)
1 /*
2  * Copyright (c) 2016 - 2018, 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 
39 /**
40  * @brief Command byte used to read status register.
41  *
42  */
43 #define QSPI_STD_CMD_RDSR 0x05
44 
45 /**
46  * @brief Byte used to mask status register and retrieve the write-in-progess bit.
47  *
48  */
49 #define QSPI_MEM_STATUSREG_WIP_Pos 0x01
50 
51 /**
52  * @brief Default time used in timeout function.
53  */
54 #define QSPI_DEF_WAIT_TIME_US 10
55 
56 /**
57  * @brief Default number of tries in timeout function.
58  */
59 #define QSPI_DEF_WAIT_ATTEMPTS 100
60 
61 /**
62   * @brief Control block - driver instance local data.
63   */
64 typedef struct
65 {
66     nrfx_qspi_handler_t handler;          /**< Handler. */
67     nrfx_drv_state_t    state;            /**< Driver state. */
68     volatile bool       interrupt_driven; /**< Information if the current operation is performed and is interrupt-driven. */
69     void *              p_context;        /**< Driver context used in interrupt. */
70 } qspi_control_block_t;
71 
72 static qspi_control_block_t m_cb;
73 
qspi_task_perform(nrf_qspi_task_t task)74 static nrfx_err_t qspi_task_perform(nrf_qspi_task_t task)
75 {
76     // Wait for peripheral
77     if (m_cb.interrupt_driven)
78     {
79         return NRFX_ERROR_BUSY;
80     }
81 
82     nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
83 
84     if (m_cb.handler)
85     {
86         m_cb.interrupt_driven = true;
87         nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
88     }
89 
90     nrf_qspi_task_trigger(NRF_QSPI, task);
91 
92     if (m_cb.handler == NULL)
93     {
94         while (!nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY))
95         {};
96     }
97     return NRFX_SUCCESS;
98 }
99 
qspi_pins_configure(nrf_qspi_pins_t const * p_config)100 static bool qspi_pins_configure(nrf_qspi_pins_t const * p_config)
101 {
102     // Check if the user set meaningful values to struct fields. If not, return false.
103     if ((p_config->sck_pin == NRF_QSPI_PIN_NOT_CONNECTED) ||
104         (p_config->csn_pin == NRF_QSPI_PIN_NOT_CONNECTED) ||
105         (p_config->io0_pin == NRF_QSPI_PIN_NOT_CONNECTED) ||
106         (p_config->io1_pin == NRF_QSPI_PIN_NOT_CONNECTED))
107     {
108         return false;
109     }
110 
111     nrf_qspi_pins_set(NRF_QSPI, p_config);
112 
113     return true;
114 }
115 
nrfx_qspi_init(nrfx_qspi_config_t const * p_config,nrfx_qspi_handler_t handler,void * p_context)116 nrfx_err_t nrfx_qspi_init(nrfx_qspi_config_t const * p_config,
117                           nrfx_qspi_handler_t        handler,
118                           void *                     p_context)
119 {
120     NRFX_ASSERT(p_config);
121     if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
122     {
123         return NRFX_ERROR_INVALID_STATE;
124     }
125 
126     if (!qspi_pins_configure(&p_config->pins))
127     {
128         return NRFX_ERROR_INVALID_PARAM;
129     }
130 
131     nrf_qspi_xip_offset_set(NRF_QSPI, p_config->xip_offset);
132     nrf_qspi_ifconfig0_set(NRF_QSPI, &p_config->prot_if);
133     nrf_qspi_ifconfig1_set(NRF_QSPI, &p_config->phy_if);
134 
135     m_cb.interrupt_driven = false;
136     m_cb.handler = handler;
137     m_cb.p_context = p_context;
138 
139     /* QSPI interrupt is disabled because the device should be enabled in polling mode (wait for activate
140        task event ready)*/
141     nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
142 
143     if (handler)
144     {
145         NRFX_IRQ_PRIORITY_SET(QSPI_IRQn, p_config->irq_priority);
146         NRFX_IRQ_ENABLE(QSPI_IRQn);
147     }
148 
149     m_cb.state = NRFX_DRV_STATE_INITIALIZED;
150 
151     nrf_qspi_enable(NRF_QSPI);
152 
153     nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
154     nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_ACTIVATE);
155 
156     // Waiting for the peripheral to activate
157     bool result;
158     NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY),
159                   QSPI_DEF_WAIT_ATTEMPTS,
160                   QSPI_DEF_WAIT_TIME_US,
161                   result);
162 
163     if (!result)
164     {
165         return NRFX_ERROR_TIMEOUT;
166     }
167 
168     return NRFX_SUCCESS;
169 }
170 
nrfx_qspi_cinstr_xfer(nrf_qspi_cinstr_conf_t const * p_config,void const * p_tx_buffer,void * p_rx_buffer)171 nrfx_err_t nrfx_qspi_cinstr_xfer(nrf_qspi_cinstr_conf_t const * p_config,
172                                  void const *                   p_tx_buffer,
173                                  void *                         p_rx_buffer)
174 {
175     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
176 
177     if (m_cb.interrupt_driven)
178     {
179         return NRFX_ERROR_BUSY;
180     }
181 
182     nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
183     /* In some cases, only opcode should be sent. To prevent execution, set function code is
184      * surrounded by an if.
185      */
186     if (p_tx_buffer)
187     {
188         nrf_qspi_cinstrdata_set(NRF_QSPI, p_config->length, p_tx_buffer);
189     }
190     nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
191 
192     nrf_qspi_cinstr_transfer_start(NRF_QSPI, p_config);
193 
194     bool result;
195     NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY),
196                   QSPI_DEF_WAIT_ATTEMPTS,
197                   QSPI_DEF_WAIT_TIME_US,
198                   result);
199 
200     if (!result)
201     {
202         // This timeout should never occur when WIPWAIT is not active, since in this
203         // case the QSPI peripheral should send the command immediately, without any
204         // waiting for previous write to complete.
205         NRFX_ASSERT(p_config->wipwait);
206 
207         return NRFX_ERROR_TIMEOUT;
208     }
209     nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
210     nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
211 
212     if (p_rx_buffer)
213     {
214         nrf_qspi_cinstrdata_get(NRF_QSPI, p_config->length, p_rx_buffer);
215     }
216 
217     return NRFX_SUCCESS;
218 }
219 
nrfx_qspi_cinstr_quick_send(uint8_t opcode,nrf_qspi_cinstr_len_t length,void const * p_tx_buffer)220 nrfx_err_t nrfx_qspi_cinstr_quick_send(uint8_t               opcode,
221                                        nrf_qspi_cinstr_len_t length,
222                                        void const *          p_tx_buffer)
223 {
224     nrf_qspi_cinstr_conf_t config = NRFX_QSPI_DEFAULT_CINSTR(opcode, length);
225     return nrfx_qspi_cinstr_xfer(&config, p_tx_buffer, NULL);
226 }
227 
nrfx_qspi_mem_busy_check(void)228 nrfx_err_t nrfx_qspi_mem_busy_check(void)
229 {
230     nrfx_err_t ret_code;
231     uint8_t status_value = 0;
232 
233     nrf_qspi_cinstr_conf_t const config =
234         NRFX_QSPI_DEFAULT_CINSTR(QSPI_STD_CMD_RDSR,
235                                  NRF_QSPI_CINSTR_LEN_2B);
236     ret_code = nrfx_qspi_cinstr_xfer(&config, &status_value, &status_value);
237 
238     if (ret_code != NRFX_SUCCESS)
239     {
240         return ret_code;
241     }
242 
243     if ((status_value & QSPI_MEM_STATUSREG_WIP_Pos) != 0x00)
244     {
245         return NRFX_ERROR_BUSY;
246     }
247 
248     return NRFX_SUCCESS;
249 }
250 
nrfx_qspi_uninit(void)251 void nrfx_qspi_uninit(void)
252 {
253     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
254 
255     nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
256 
257     nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_DEACTIVATE);
258 
259     nrf_qspi_disable(NRF_QSPI);
260 
261     NRFX_IRQ_DISABLE(QSPI_IRQn);
262 
263     nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
264 
265     m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
266 }
267 
nrfx_qspi_write(void const * p_tx_buffer,size_t tx_buffer_length,uint32_t dst_address)268 nrfx_err_t nrfx_qspi_write(void const * p_tx_buffer,
269                            size_t       tx_buffer_length,
270                            uint32_t     dst_address)
271 {
272     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
273     NRFX_ASSERT(p_tx_buffer != NULL);
274     NRFX_ASSERT(nrfx_is_in_ram(p_tx_buffer));
275     NRFX_ASSERT(nrfx_is_word_aligned(p_tx_buffer));
276 
277     if (!nrfx_is_in_ram(p_tx_buffer))
278     {
279         return NRFX_ERROR_INVALID_ADDR;
280     }
281 
282     nrf_qspi_write_buffer_set(NRF_QSPI, p_tx_buffer, tx_buffer_length, dst_address);
283     return qspi_task_perform(NRF_QSPI_TASK_WRITESTART);
284 
285 }
286 
nrfx_qspi_read(void * p_rx_buffer,size_t rx_buffer_length,uint32_t src_address)287 nrfx_err_t nrfx_qspi_read(void *   p_rx_buffer,
288                           size_t   rx_buffer_length,
289                           uint32_t src_address)
290 {
291     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
292     NRFX_ASSERT(p_rx_buffer != NULL);
293     NRFX_ASSERT(nrfx_is_in_ram(p_rx_buffer));
294     NRFX_ASSERT(nrfx_is_word_aligned(p_rx_buffer));
295 
296     if (!nrfx_is_in_ram(p_rx_buffer))
297     {
298         return NRFX_ERROR_INVALID_ADDR;
299     }
300 
301     nrf_qspi_read_buffer_set(NRF_QSPI, p_rx_buffer, rx_buffer_length, src_address);
302     return qspi_task_perform(NRF_QSPI_TASK_READSTART);
303 }
304 
nrfx_qspi_erase(nrf_qspi_erase_len_t length,uint32_t start_address)305 nrfx_err_t nrfx_qspi_erase(nrf_qspi_erase_len_t length,
306                            uint32_t             start_address)
307 {
308     NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
309     nrf_qspi_erase_ptr_set(NRF_QSPI, start_address, length);
310     return qspi_task_perform(NRF_QSPI_TASK_ERASESTART);
311 }
312 
nrfx_qspi_chip_erase(void)313 nrfx_err_t nrfx_qspi_chip_erase(void)
314 {
315     return nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_ALL, 0);
316 }
317 
nrfx_qspi_irq_handler(void)318 void nrfx_qspi_irq_handler(void)
319 {
320     // Catch Event ready interrupts
321     if (nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY))
322     {
323         m_cb.interrupt_driven = false;
324         nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
325         m_cb.handler(NRFX_QSPI_EVENT_DONE, m_cb.p_context);
326     }
327 }
328 
329 #endif // NRFX_CHECK(NRFX_QSPI_ENABLED)
330