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