Skip to content

Commit 84effb3

Browse files
committed
alif/ospi_flash: Generalise flash driver to support MX chips.
Signed-off-by: Damien George <damien@micropython.org>
1 parent 4c4b484 commit 84effb3

6 files changed

Lines changed: 643 additions & 135 deletions

File tree

ports/alif/alif.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ SRC_C = \
122122
mpu.c \
123123
mpuart.c \
124124
msc_disk.c \
125+
ospi_ext.c \
125126
ospi_flash.c \
126127
pendsv.c \
127128
system_tick.c \

ports/alif/ospi_ext.c

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2024 OpenMV LLC.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include ALIF_CMSIS_H
28+
#include "ospi_ext.h"
29+
#include "ospi_xip_user.h"
30+
31+
#define INST_L16bit (3)
32+
33+
static void ospi_xip_disable(ospi_flash_cfg_t *ospi_cfg) {
34+
ospi_cfg->aes_regs->aes_control &= ~AES_CONTROL_XIP_EN;
35+
}
36+
37+
static void ospi_xip_enable(ospi_flash_cfg_t *ospi_cfg) {
38+
ospi_cfg->aes_regs->aes_control |= AES_CONTROL_XIP_EN;
39+
#if OSPI_XIP_ENABLE_AES_DECRYPTION
40+
ospi_cfg->aes_regs->aes_control |= (AES_CONTROL_LD_KEY | AES_CONTROL_DECRYPT_EN);
41+
#endif
42+
}
43+
44+
// Standard SPI transfer.
45+
void ospi_spi_transfer(ospi_flash_cfg_t *ospi_cfg, size_t len, const uint8_t *buf_out, uint8_t *buf_in) {
46+
ospi_writel(ospi_cfg, ser, 0);
47+
spi_disable(ospi_cfg);
48+
49+
uint32_t ctrlr0 = CTRLR0_IS_MST
50+
| (SINGLE << CTRLR0_SPI_FRF_OFFSET)
51+
| (SPI_TMOD_TR << CTRLR0_TMOD_OFFSET)
52+
| (CTRLR0_DFS_8bit << CTRLR0_DFS_OFFSET)
53+
;
54+
55+
uint32_t spi_ctrlr0 = TRANS_TYPE_STANDARD;
56+
57+
ospi_writel(ospi_cfg, ctrlr0, ctrlr0);
58+
ospi_writel(ospi_cfg, ctrlr1, len - 1);
59+
ospi_writel(ospi_cfg, spi_ctrlr0, spi_ctrlr0);
60+
spi_enable(ospi_cfg);
61+
62+
// Buffer output data in SPI FIFO.
63+
for (int i = 0; i < len; ++i) {
64+
ospi_writel(ospi_cfg, data_reg, buf_out[i]);
65+
}
66+
67+
// Enable the SPI peripheral.
68+
ospi_writel(ospi_cfg, ser, ospi_cfg->ser);
69+
70+
// Read in data.
71+
for (int i = 0; i < len; ++i) {
72+
unsigned int timeout = 100000;
73+
while (ospi_readl(ospi_cfg, rxflr) == 0) {
74+
if (--timeout == 0) {
75+
return;
76+
}
77+
}
78+
buf_in[i] = ospi_readl(ospi_cfg, data_reg);
79+
}
80+
}
81+
82+
void ospi_setup_read_ext(ospi_flash_cfg_t *ospi_cfg, bool rxds, uint32_t inst_len, uint32_t addr_len, uint32_t data_len, uint32_t read_len, uint32_t wait_cycles) {
83+
ospi_writel(ospi_cfg, ser, 0);
84+
spi_disable(ospi_cfg);
85+
86+
uint32_t val = CTRLR0_IS_MST
87+
| (OCTAL << CTRLR0_SPI_FRF_OFFSET)
88+
| (TMOD_RO << CTRLR0_TMOD_OFFSET)
89+
| (data_len << CTRLR0_DFS_OFFSET);
90+
91+
ospi_writel(ospi_cfg, ctrlr0, val);
92+
ospi_writel(ospi_cfg, ctrlr1, read_len - 1);
93+
94+
if (ospi_cfg->ddr_en) {
95+
val = TRANS_TYPE_FRF_DEFINED
96+
| (rxds << CTRLR0_SPI_RXDS_EN_OFFSET)
97+
| (1 << CTRLR0_SPI_DDR_EN_OFFSET)
98+
| (inst_len << CTRLR0_INST_L_OFFSET)
99+
| (addr_len << CTRLR0_ADDR_L_OFFSET)
100+
| (wait_cycles << CTRLR0_WAIT_CYCLES_OFFSET);
101+
if (inst_len == OSPI_INST_L_16bit) {
102+
val |= 1 << CTRLR0_INST_DDR_EN_OFFSET;
103+
}
104+
} else {
105+
val = TRANS_TYPE_FRF_DEFINED
106+
| (rxds << CTRLR0_SPI_RXDS_EN_OFFSET)
107+
| (inst_len << CTRLR0_INST_L_OFFSET)
108+
| (addr_len << CTRLR0_ADDR_L_OFFSET)
109+
| (wait_cycles << CTRLR0_WAIT_CYCLES_OFFSET);
110+
}
111+
112+
ospi_writel(ospi_cfg, spi_ctrlr0, val);
113+
ospi_cfg->rx_req = read_len;
114+
spi_enable(ospi_cfg);
115+
}
116+
117+
int ospi_recv_blocking_8bit_data(ospi_flash_cfg_t *ospi_cfg, uint32_t command, uint8_t *buffer) {
118+
ospi_writel(ospi_cfg, data_reg, command);
119+
ospi_writel(ospi_cfg, ser, ospi_cfg->ser);
120+
121+
ospi_cfg->rx_cnt = 0;
122+
123+
while (ospi_cfg->rx_cnt < ospi_cfg->rx_req) {
124+
unsigned int timeout = 100000;
125+
while (ospi_readl(ospi_cfg, rxflr) == 0) {
126+
if (--timeout == 0) {
127+
return -OSPI_ETIMEDOUT;
128+
}
129+
}
130+
*buffer++ = ospi_readl(ospi_cfg, data_reg);
131+
ospi_cfg->rx_cnt++;
132+
}
133+
134+
return 0;
135+
}
136+
137+
int ospi_recv_blocking_16bit_data(ospi_flash_cfg_t *ospi_cfg, uint32_t command, uint16_t *buffer) {
138+
ospi_writel(ospi_cfg, data_reg, command);
139+
ospi_writel(ospi_cfg, ser, ospi_cfg->ser);
140+
141+
ospi_cfg->rx_cnt = 0;
142+
143+
while (ospi_cfg->rx_cnt < ospi_cfg->rx_req) {
144+
unsigned int timeout = 100000;
145+
while (ospi_readl(ospi_cfg, rxflr) == 0) {
146+
if (--timeout == 0) {
147+
return -OSPI_ETIMEDOUT;
148+
}
149+
}
150+
*buffer++ = ospi_readl(ospi_cfg, data_reg);
151+
ospi_cfg->rx_cnt++;
152+
}
153+
154+
return 0;
155+
}
156+
157+
int ospi_recv_blocking_32bit_data(ospi_flash_cfg_t *ospi_cfg, uint32_t command, uint32_t *buffer) {
158+
ospi_writel(ospi_cfg, data_reg, command);
159+
ospi_writel(ospi_cfg, ser, ospi_cfg->ser);
160+
161+
ospi_cfg->rx_cnt = 0;
162+
163+
while (ospi_cfg->rx_cnt < ospi_cfg->rx_req) {
164+
unsigned int timeout = 100000;
165+
while (ospi_readl(ospi_cfg, rxflr) == 0) {
166+
if (--timeout == 0) {
167+
return -OSPI_ETIMEDOUT;
168+
}
169+
}
170+
*buffer++ = __ROR(ospi_readl(ospi_cfg, data_reg), 16);
171+
ospi_cfg->rx_cnt++;
172+
}
173+
174+
return 0;
175+
}
176+
177+
void ospi_setup_write_ext(ospi_flash_cfg_t *ospi_cfg, bool rxds, uint32_t inst_len, uint32_t addr_len, uint32_t data_len) {
178+
ospi_writel(ospi_cfg, ser, 0);
179+
spi_disable(ospi_cfg);
180+
181+
uint32_t val = CTRLR0_IS_MST
182+
| (OCTAL << CTRLR0_SPI_FRF_OFFSET)
183+
| (TMOD_TO << CTRLR0_TMOD_OFFSET)
184+
| (data_len << CTRLR0_DFS_OFFSET);
185+
186+
ospi_writel(ospi_cfg, ctrlr0, val);
187+
ospi_writel(ospi_cfg, ctrlr1, 0);
188+
189+
if (ospi_cfg->ddr_en) {
190+
val = TRANS_TYPE_FRF_DEFINED
191+
| (rxds << CTRLR0_SPI_RXDS_EN_OFFSET)
192+
| (1 << CTRLR0_SPI_DDR_EN_OFFSET)
193+
| (inst_len << CTRLR0_INST_L_OFFSET)
194+
| (addr_len << CTRLR0_ADDR_L_OFFSET)
195+
| (0 << CTRLR0_WAIT_CYCLES_OFFSET);
196+
if (inst_len == OSPI_INST_L_16bit) {
197+
val |= 1 << CTRLR0_INST_DDR_EN_OFFSET;
198+
}
199+
} else {
200+
val = TRANS_TYPE_FRF_DEFINED
201+
| (rxds << CTRLR0_SPI_RXDS_EN_OFFSET)
202+
| (inst_len << CTRLR0_INST_L_OFFSET)
203+
| (addr_len << CTRLR0_ADDR_L_OFFSET)
204+
| (0 << CTRLR0_WAIT_CYCLES_OFFSET);
205+
}
206+
207+
ospi_writel(ospi_cfg, spi_ctrlr0, val);
208+
spi_enable(ospi_cfg);
209+
}
210+
211+
void ospi_xip_enter_16bit_cmd(ospi_flash_cfg_t *ospi_cfg, uint32_t data_len, uint16_t incr_command, uint16_t wrap_command, uint16_t read_dummy_cycles) {
212+
spi_disable(ospi_cfg);
213+
214+
uint32_t val = CTRLR0_IS_MST
215+
| (OCTAL << CTRLR0_SPI_FRF_OFFSET)
216+
| (0 << CTRLR0_SCPOL_OFFSET)
217+
| (0 << CTRLR0_SCPH_OFFSET)
218+
| (0 << CTRLR0_SSTE_OFFSET)
219+
| (TMOD_RO << CTRLR0_TMOD_OFFSET)
220+
| (data_len << CTRLR0_DFS_OFFSET);
221+
222+
ospi_writel(ospi_cfg, ctrlr0, val);
223+
224+
val = (OCTAL << XIP_CTRL_FRF_OFFSET)
225+
| (0x2 << XIP_CTRL_TRANS_TYPE_OFFSET)
226+
| (ADDR_L32bit << XIP_CTRL_ADDR_L_OFFSET)
227+
| (INST_L16bit << XIP_CTRL_INST_L_OFFSET)
228+
| (0x0 << XIP_CTRL_MD_BITS_EN_OFFSET)
229+
| (read_dummy_cycles << XIP_CTRL_WAIT_CYCLES_OFFSET)
230+
| (0x1 << XIP_CTRL_DFC_HC_OFFSET)
231+
| (ospi_cfg->ddr_en << XIP_CTRL_DDR_EN_OFFSET)
232+
| (ospi_cfg->ddr_en << XIP_CTRL_INST_DDR_EN_OFFSET)
233+
| (0x1 << XIP_CTRL_RXDS_EN_OFFSET)
234+
| (0x1 << XIP_CTRL_INST_EN_OFFSET)
235+
| (0x0 << XIP_CTRL_CONT_XFER_EN_OFFSET)
236+
| (0x0 << XIP_CTRL_HYPERBUS_EN_OFFSET)
237+
| (0x1 << XIP_CTRL_RXDS_SIG_EN)
238+
| (0x0 << XIP_CTRL_XIP_MBL_OFFSET)
239+
| (0x0 << XIP_PREFETCH_EN_OFFSET)
240+
| (0x0 << XIP_CTRL_RXDS_VL_EN_OFFSET);
241+
242+
ospi_writel(ospi_cfg, xip_ctrl, val);
243+
244+
ospi_writel(ospi_cfg, rx_sample_dly, 4);
245+
ospi_writel(ospi_cfg, txd_drive_edge, 1);
246+
ospi_cfg->aes_regs->aes_rxds_delay = OSPI_XIP_RXDS_DELAY;
247+
248+
ospi_writel(ospi_cfg, xip_mode_bits, 0x0);
249+
ospi_writel(ospi_cfg, xip_incr_inst, incr_command);
250+
ospi_writel(ospi_cfg, xip_wrap_inst, wrap_command);
251+
ospi_writel(ospi_cfg, xip_ser, ospi_cfg->ser);
252+
253+
spi_enable(ospi_cfg);
254+
ospi_xip_enable(ospi_cfg);
255+
}
256+
257+
void ospi_xip_exit_16bit_cmd(ospi_flash_cfg_t *ospi_cfg, uint16_t incr_command, uint16_t wrap_command) {
258+
spi_disable(ospi_cfg);
259+
260+
uint32_t val = CTRLR0_IS_MST
261+
| (OCTAL << CTRLR0_SPI_FRF_OFFSET)
262+
| (0 << CTRLR0_SCPOL_OFFSET)
263+
| (0 << CTRLR0_SCPH_OFFSET)
264+
| (0 << CTRLR0_SSTE_OFFSET)
265+
| (TMOD_RO << CTRLR0_TMOD_OFFSET)
266+
| (CTRLR0_DFS_32bit << CTRLR0_DFS_OFFSET);
267+
268+
ospi_writel(ospi_cfg, ctrlr0, val);
269+
270+
val = TRANS_TYPE_FRF_DEFINED
271+
| ((ospi_cfg->ddr_en) << CTRLR0_SPI_DDR_EN_OFFSET)
272+
| (2 << CTRLR0_XIP_MBL_OFFSET)
273+
| (1 << CTRLR0_XIP_DFS_HC_OFFSET)
274+
| (1 << CTRLR0_XIP_INST_EN_OFFSET)
275+
| (CTRLR0_INST_L_16bit << CTRLR0_INST_L_OFFSET)
276+
| (ospi_cfg->addrlen) << (CTRLR0_ADDR_L_OFFSET)
277+
| (ospi_cfg->wait_cycles << CTRLR0_WAIT_CYCLES_OFFSET);
278+
279+
ospi_writel(ospi_cfg, spi_ctrlr0, val);
280+
281+
ospi_writel(ospi_cfg, xip_mode_bits, 0x1);
282+
ospi_writel(ospi_cfg, xip_incr_inst, incr_command);
283+
ospi_writel(ospi_cfg, xip_wrap_inst, wrap_command);
284+
ospi_writel(ospi_cfg, xip_ser, ospi_cfg->ser);
285+
ospi_writel(ospi_cfg, ser, ospi_cfg->ser);
286+
ospi_writel(ospi_cfg, xip_cnt_time_out, 100);
287+
288+
spi_enable(ospi_cfg);
289+
290+
ospi_xip_enable(ospi_cfg);
291+
ospi_xip_disable(ospi_cfg);
292+
}

ports/alif/ospi_ext.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2024 OpenMV LLC.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
#ifndef MICROPY_INCLUDED_ALIF_OSPI_EXT_H
27+
#define MICROPY_INCLUDED_ALIF_OSPI_EXT_H
28+
29+
#include <stddef.h>
30+
#include "ospi_drv.h"
31+
32+
#define OSPI_ETIMEDOUT (110)
33+
34+
#define OSPI_INST_L_8bit (CTRLR0_INST_L_8bit)
35+
#define OSPI_INST_L_16bit (CTRLR0_INST_L_16bit)
36+
37+
#define OSPI_ADDR_L_0bit UINT32_C(0x0)
38+
#define OSPI_ADDR_L_24bit UINT32_C(0x6)
39+
#define OSPI_ADDR_L_32bit UINT32_C(0x8)
40+
41+
#define OSPI_DATA_L_8bit (CTRLR0_DFS_8bit)
42+
#define OSPI_DATA_L_16bit (CTRLR0_DFS_16bit)
43+
#define OSPI_DATA_L_32bit (CTRLR0_DFS_32bit)
44+
45+
void ospi_spi_transfer(ospi_flash_cfg_t *ospi_cfg, size_t len, const uint8_t *buf_out, uint8_t *buf_in);
46+
47+
void ospi_setup_read_ext(ospi_flash_cfg_t *ospi_cfg, bool rxds, uint32_t inst_len, uint32_t addr_len, uint32_t data_len, uint32_t read_len, uint32_t wait_cycles);
48+
int ospi_recv_blocking_8bit_data(ospi_flash_cfg_t *ospi_cfg, uint32_t command, uint8_t *buffer);
49+
int ospi_recv_blocking_16bit_data(ospi_flash_cfg_t *ospi_cfg, uint32_t command, uint16_t *buffer);
50+
int ospi_recv_blocking_32bit_data(ospi_flash_cfg_t *ospi_cfg, uint32_t command, uint32_t *buffer);
51+
52+
void ospi_setup_write_ext(ospi_flash_cfg_t *ospi_cfg, bool rxds, uint32_t inst_len, uint32_t addr_len, uint32_t data_len);
53+
54+
void ospi_xip_enter_16bit_cmd(ospi_flash_cfg_t *ospi_cfg, uint32_t data_len, uint16_t incr_command, uint16_t wrap_command, uint16_t read_dummy_cycles);
55+
void ospi_xip_exit_16bit_cmd(ospi_flash_cfg_t *ospi_cfg, uint16_t incr_command, uint16_t wrap_command);
56+
57+
#endif // MICROPY_INCLUDED_ALIF_OSPI_EXT_H

0 commit comments

Comments
 (0)