32
32
#include "qspi.h"
33
33
#include "pin_static_af.h"
34
34
35
- #if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 )
35
+ #if MICROPY_HW_ENABLE_QSPI || defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 )
36
36
37
37
#define QSPI_MAP_ADDR (0x90000000)
38
38
52
52
#define MICROPY_HW_QSPI_CS_HIGH_CYCLES 2 // nCS stays high for 2 cycles
53
53
#endif
54
54
55
- #ifndef MICROPY_HW_QSPI_MPU_REGION_SIZE
56
- #define MICROPY_HW_QSPI_MPU_REGION_SIZE ((1 << (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3)) >> 20)
55
+ #ifndef MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2
57
56
#endif
58
57
59
- #if (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1 ) >= 24
60
- #define QSPI_CMD 0xec
61
- #define QSPI_ADSIZE 3
62
- #else
63
- #define QSPI_CMD 0xeb
64
- #define QSPI_ADSIZE 2
65
- #endif
58
+ // Fast Read command in 32bit and 24bit addressing.
59
+ #define QSPI_FAST_READ_A4_CMD 0xec
60
+ #define QSPI_FAST_READ_A3_CMD 0xeb
61
+
62
+ // this formula computes the log2 of "m"
63
+ #define BITS_TO_LOG2 (m ) ((m) - 1) / (((m) - 1) % 255 + 1) / 255 % 255 * 8 + 7 - 86 / (((m) - 1) % 255 + 12)
64
+
65
+ #define MBytes (1024 * 1024)
66
+ static size_t qspi_memory_size_bytes = 0 ;
66
67
67
68
static inline void qspi_mpu_disable_all (void ) {
68
69
// Configure MPU to disable access to entire QSPI region, to prevent CPU
@@ -72,7 +73,48 @@ static inline void qspi_mpu_disable_all(void) {
72
73
mpu_config_end (irq_state );
73
74
}
74
75
75
- static inline void qspi_mpu_enable_mapped (void ) {
76
+ #if 1
77
+
78
+ static inline void qspi_mpu_enable_mapped () {
79
+ // Configure MPU to allow access to only the valid part of external SPI flash.
80
+ // The memory accesses to the mapped QSPI are faster if the MPU is not used
81
+ // unprivileged or the background region is disabled, the MPU issues a fault.
82
+ uint32_t irq_state = mpu_config_start ();
83
+
84
+ if (qspi_memory_size_bytes > (128 * MBytes )) {
85
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0xFF , MPU_REGION_SIZE_256MB ));
86
+ } else if (qspi_memory_size_bytes > (64 * MBytes )) {
87
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x0F , MPU_REGION_SIZE_256MB ));
88
+ } else if (qspi_memory_size_bytes > (32 * MBytes )) {
89
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x03 , MPU_REGION_SIZE_256MB ));
90
+ } else if (qspi_memory_size_bytes > (16 * MBytes )) {
91
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
92
+ } else if (qspi_memory_size_bytes > (8 * MBytes )) {
93
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
94
+ mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x0F , MPU_REGION_SIZE_32MB ));
95
+ } else if (qspi_memory_size_bytes > (4 * MBytes )) {
96
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
97
+ mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x03 , MPU_REGION_SIZE_32MB ));
98
+ } else if (qspi_memory_size_bytes > (2 * MBytes )) {
99
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
100
+ mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_32MB ));
101
+ } else if (qspi_memory_size_bytes > (1 * MBytes )) {
102
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
103
+ mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x0F , MPU_REGION_SIZE_32MB ));
104
+ mpu_config_region (MPU_REGION_QSPI3 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_16MB ));
105
+ } else {
106
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
107
+ mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_32MB ));
108
+ mpu_config_region (MPU_REGION_QSPI3 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x03 , MPU_REGION_SIZE_4MB ));
109
+ }
110
+ mpu_config_end (irq_state );
111
+ }
112
+
113
+ #else
114
+
115
+ // This variant of the function is harder to read, but 76 bytes smaller.
116
+
117
+ static inline void qspi_mpu_enable_mapped () {
76
118
// Configure MPU to allow access to only the valid part of external SPI flash.
77
119
// The memory accesses to the mapped QSPI are faster if the MPU is not used
78
120
// for the memory-mapped region, so 3 MPU regions are used to disable access
@@ -83,36 +125,61 @@ static inline void qspi_mpu_enable_mapped(void) {
83
125
// other enabled region overlaps the disabled subregion, and the access is
84
126
// unprivileged or the background region is disabled, the MPU issues a fault.
85
127
uint32_t irq_state = mpu_config_start ();
86
- #if MICROPY_HW_QSPI_MPU_REGION_SIZE > 128
87
- mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0xFF , MPU_REGION_SIZE_256MB ));
88
- #elif MICROPY_HW_QSPI_MPU_REGION_SIZE > 64
89
- mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x0F , MPU_REGION_SIZE_256MB ));
90
- #elif MICROPY_HW_QSPI_MPU_REGION_SIZE > 32
91
- mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x03 , MPU_REGION_SIZE_256MB ));
92
- #elif MICROPY_HW_QSPI_MPU_REGION_SIZE > 16
93
- mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
94
- #elif MICROPY_HW_QSPI_MPU_REGION_SIZE > 8
95
- mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
96
- mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x0F , MPU_REGION_SIZE_32MB ));
97
- #elif MICROPY_HW_QSPI_MPU_REGION_SIZE > 4
98
- mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
99
- mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x03 , MPU_REGION_SIZE_32MB ));
100
- #elif MICROPY_HW_QSPI_MPU_REGION_SIZE > 2
101
- mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
102
- mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_32MB ));
103
- #elif MICROPY_HW_QSPI_MPU_REGION_SIZE > 1
104
- mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
105
- mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x0F , MPU_REGION_SIZE_32MB ));
106
- mpu_config_region (MPU_REGION_QSPI3 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_16MB ));
107
- #else
108
- mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_256MB ));
109
- mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x01 , MPU_REGION_SIZE_32MB ));
110
- mpu_config_region (MPU_REGION_QSPI3 , QSPI_MAP_ADDR , MPU_CONFIG_DISABLE (0x03 , MPU_REGION_SIZE_4MB ));
111
- #endif
128
+
129
+ static const uint8_t region_definitions [][7 ] = {
130
+ // Each row per MB region total size, specifying region srd and size for MPU_REGION_QSPI1, 2 and 3.
131
+ {128 , 0xFF , MPU_REGION_SIZE_256MB , 0 , 0 , 0 , 0 },
132
+ { 64 , 0x0F , MPU_REGION_SIZE_256MB , 0 , 0 , 0 , 0 },
133
+ { 32 , 0x03 , MPU_REGION_SIZE_256MB , 0 , 0 , 0 , 0 },
134
+ { 16 , 0x01 , MPU_REGION_SIZE_256MB , 0 , 0 , 0 , 0 },
135
+ { 8 , 0x01 , MPU_REGION_SIZE_256MB ,
136
+ 0x0F , MPU_REGION_SIZE_32MB , 0 , 0 },
137
+ { 4 , 0x01 , MPU_REGION_SIZE_256MB ,
138
+ 0x03 , MPU_REGION_SIZE_32MB , 0 , 0 },
139
+ { 2 , 0x01 , MPU_REGION_SIZE_256MB ,
140
+ 0x01 , MPU_REGION_SIZE_32MB , 0 , 0 },
141
+ { 1 , 0x01 , MPU_REGION_SIZE_256MB ,
142
+ 0x0F , MPU_REGION_SIZE_32MB ,
143
+ 0x01 , MPU_REGION_SIZE_16MB },
144
+ { 0 , 0x01 , MPU_REGION_SIZE_256MB ,
145
+ 0x01 , MPU_REGION_SIZE_32MB ,
146
+ 0x03 , MPU_REGION_SIZE_4MB },
147
+ };
148
+ size_t qspi_memory_size_mbytes = qspi_memory_size_bytes / 1024 / 1024 ;
149
+
150
+ for (uint8_t i = 0 ; i < 9 ; ++ i ) {
151
+ if (qspi_memory_size_mbytes > region_definitions [i ][0 ]) {
152
+ uint32_t attr_size_1 = MPU_CONFIG_DISABLE (region_definitions [i ][1 ], region_definitions [i ][2 ]);
153
+ mpu_config_region (MPU_REGION_QSPI1 , QSPI_MAP_ADDR , attr_size_1 );
154
+ if (region_definitions [i ][3 ] > 0 ) {
155
+ uint32_t attr_size_2 = MPU_CONFIG_DISABLE (region_definitions [i ][3 ], region_definitions [i ][4 ]);
156
+ mpu_config_region (MPU_REGION_QSPI2 , QSPI_MAP_ADDR , attr_size_2 );
157
+ }
158
+ if (region_definitions [i ][5 ] > 0 ) {
159
+ uint32_t attr_size_3 = MPU_CONFIG_DISABLE (region_definitions [i ][5 ], region_definitions [i ][6 ]);
160
+ mpu_config_region (MPU_REGION_QSPI3 , QSPI_MAP_ADDR , attr_size_3 );
161
+ }
162
+ break ;
163
+ }
164
+ }
112
165
mpu_config_end (irq_state );
113
166
}
114
167
115
- void qspi_init (void ) {
168
+ #endif
169
+
170
+ void qspi_set_memory_size (size_t memory_size_bytes ) {
171
+ qspi_memory_size_bytes = memory_size_bytes ;
172
+ size_t QSPIFLASH_SIZE_BITS_LOG2 = BITS_TO_LOG2 (qspi_memory_size_bytes * 8 );
173
+ QUADSPI -> DCR =
174
+ (QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1 ) << QUADSPI_DCR_FSIZE_Pos
175
+ | (MICROPY_HW_QSPI_CS_HIGH_CYCLES - 1 ) << QUADSPI_DCR_CSHT_Pos
176
+ | 0 << QUADSPI_DCR_CKMODE_Pos // CLK idles at low state
177
+ ;
178
+ }
179
+
180
+ void qspi_init (size_t memory_size_bytes ) {
181
+ qspi_memory_size_bytes = memory_size_bytes ;
182
+
116
183
qspi_mpu_disable_all ();
117
184
118
185
// Configure pins
@@ -143,15 +210,20 @@ void qspi_init(void) {
143
210
| 1 << QUADSPI_CR_EN_Pos // enable the peripheral
144
211
;
145
212
146
- QUADSPI -> DCR =
147
- (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1 ) << QUADSPI_DCR_FSIZE_Pos
148
- | (MICROPY_HW_QSPI_CS_HIGH_CYCLES - 1 ) << QUADSPI_DCR_CSHT_Pos
149
- | 0 << QUADSPI_DCR_CKMODE_Pos // CLK idles at low state
150
- ;
213
+ if (qspi_memory_size_bytes ) {
214
+ qspi_set_memory_size (qspi_memory_size_bytes );
215
+ }
151
216
}
152
217
153
- void qspi_memory_map (void ) {
218
+ void qspi_memory_map () {
154
219
// Enable memory-mapped mode
220
+ uint8_t cmd = QSPI_FAST_READ_A3_CMD ;
221
+ uint8_t adsize = 2 ;
222
+ if (qspi_memory_size_bytes > (16 * MBytes )) {
223
+ // Flash chips over 16MB require 32bit addressing.
224
+ cmd = QSPI_FAST_READ_A4_CMD ;
225
+ adsize = 3 ;
226
+ }
155
227
156
228
QUADSPI -> ABR = 0 ; // disable continuous read mode
157
229
@@ -163,20 +235,20 @@ void qspi_memory_map(void) {
163
235
| 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles
164
236
| 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte
165
237
| 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines
166
- | QSPI_ADSIZE << QUADSPI_CCR_ADSIZE_Pos
238
+ | adsize << QUADSPI_CCR_ADSIZE_Pos
167
239
| 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines
168
240
| 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
169
- | QSPI_CMD << QUADSPI_CCR_INSTRUCTION_Pos
241
+ | cmd << QUADSPI_CCR_INSTRUCTION_Pos
170
242
;
171
243
172
244
qspi_mpu_enable_mapped ();
173
245
}
174
246
175
- STATIC int qspi_ioctl (void * self_in , uint32_t cmd ) {
247
+ STATIC int qspi_ioctl (void * self_in , uint32_t cmd , uint32_t arg ) {
176
248
(void )self_in ;
177
249
switch (cmd ) {
178
250
case MP_QSPI_IOCTL_INIT :
179
- qspi_init ();
251
+ qspi_init (0 );
180
252
break ;
181
253
case MP_QSPI_IOCTL_BUS_ACQUIRE :
182
254
// Disable memory-mapped region during bus access
@@ -192,6 +264,11 @@ STATIC int qspi_ioctl(void *self_in, uint32_t cmd) {
192
264
// Switch to memory-map mode when bus is idle
193
265
qspi_memory_map ();
194
266
break ;
267
+ case MP_QSPI_IOCTL_FLASH_SIZE :
268
+ if (arg > 0 ) {
269
+ qspi_set_memory_size (arg );
270
+ }
271
+ return qspi_memory_size_bytes ;
195
272
}
196
273
return 0 ; // success
197
274
}
0 commit comments