Skip to content

Commit 860cfba

Browse files
author
Andrew Leech
committed
stm32/qspi: Use the flash size configured in spiflash init.
Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
1 parent 8cb5f0c commit 860cfba

File tree

6 files changed

+138
-55
lines changed

6 files changed

+138
-55
lines changed

drivers/bus/qspi.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ enum {
3737
MP_QSPI_IOCTL_DEINIT,
3838
MP_QSPI_IOCTL_BUS_ACQUIRE,
3939
MP_QSPI_IOCTL_BUS_RELEASE,
40+
MP_QSPI_IOCTL_FLASH_SIZE,
4041
};
4142

4243
enum qspi_tranfer_mode {
@@ -45,7 +46,7 @@ enum qspi_tranfer_mode {
4546
};
4647

4748
typedef struct _mp_qspi_proto_t {
48-
int (*ioctl)(void *self, uint32_t cmd);
49+
int (*ioctl)(void *self, uint32_t cmd, uint32_t arg);
4950
int (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data);
5051
int (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src);
5152
int (*read_cmd)(void *self, uint8_t cmd, size_t len, uint32_t *dest);

drivers/bus/softqspi.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ STATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) {
5656
mp_hal_pin_write(self->io3, (v >> 3) & 1);
5757
}
5858

59-
STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) {
59+
STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd, uint32_t arg) {
6060
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
6161

6262
switch (cmd) {

drivers/memory/spiflash.c

+7-3
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,14 @@ static external_flash_device generic_config = GENERIC;
8080
STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) {
8181
const mp_spiflash_config_t *c = self->config;
8282
if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) {
83-
c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_ACQUIRE);
83+
c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_ACQUIRE, 0);
8484
}
8585
}
8686

8787
STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) {
8888
const mp_spiflash_config_t *c = self->config;
8989
if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) {
90-
c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_RELEASE);
90+
c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_RELEASE, 0);
9191
}
9292
}
9393

@@ -198,7 +198,7 @@ int mp_spiflash_init(mp_spiflash_t *self) {
198198
mp_hal_pin_output(self->config->bus.u_spi.cs);
199199
self->config->bus.u_spi.proto->ioctl(self->config->bus.u_spi.data, MP_SPI_IOCTL_INIT);
200200
} else {
201-
self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT);
201+
self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT, 0);
202202
}
203203

204204
mp_spiflash_acquire_bus(self);
@@ -327,6 +327,10 @@ int mp_spiflash_init(mp_spiflash_t *self) {
327327
}
328328
}
329329

330+
if (self->config->bus_kind == MP_SPIFLASH_BUS_QSPI) {
331+
self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_FLASH_SIZE, self->device->total_size);
332+
}
333+
330334
mp_spiflash_release_bus(self);
331335
return ret;
332336
}

ports/stm32/boards/STM32F769DISC/board_init.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "storage.h"
22
#include "qspi.h"
3+
#include "mpconfigboard.h"
34

45
// This configuration is needed for mboot to be able to write to the external QSPI flash
56

@@ -21,6 +22,6 @@ spi_bdev_t spi_bdev;
2122
// This init function is needed to memory map the QSPI flash early in the boot process
2223

2324
void board_early_init(void) {
24-
qspi_init();
25+
qspi_init(MICROPY_HW_BDEV_SPIFLASH_SIZE_BYTES);
2526
qspi_memory_map();
2627
}

ports/stm32/qspi.c

+125-48
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#include "qspi.h"
3333
#include "pin_static_af.h"
3434

35-
#if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2)
35+
#if MICROPY_HW_ENABLE_QSPI || defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2)
3636

3737
#define QSPI_MAP_ADDR (0x90000000)
3838

@@ -52,17 +52,18 @@
5252
#define MICROPY_HW_QSPI_CS_HIGH_CYCLES 2 // nCS stays high for 2 cycles
5353
#endif
5454

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
5756
#endif
5857

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;
6667

6768
static inline void qspi_mpu_disable_all(void) {
6869
// Configure MPU to disable access to entire QSPI region, to prevent CPU
@@ -72,7 +73,48 @@ static inline void qspi_mpu_disable_all(void) {
7273
mpu_config_end(irq_state);
7374
}
7475

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() {
76118
// Configure MPU to allow access to only the valid part of external SPI flash.
77119
// The memory accesses to the mapped QSPI are faster if the MPU is not used
78120
// 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) {
83125
// other enabled region overlaps the disabled subregion, and the access is
84126
// unprivileged or the background region is disabled, the MPU issues a fault.
85127
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+
}
112165
mpu_config_end(irq_state);
113166
}
114167

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+
116183
qspi_mpu_disable_all();
117184

118185
// Configure pins
@@ -143,15 +210,20 @@ void qspi_init(void) {
143210
| 1 << QUADSPI_CR_EN_Pos // enable the peripheral
144211
;
145212

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+
}
151216
}
152217

153-
void qspi_memory_map(void) {
218+
void qspi_memory_map() {
154219
// 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+
}
155227

156228
QUADSPI->ABR = 0; // disable continuous read mode
157229

@@ -163,20 +235,20 @@ void qspi_memory_map(void) {
163235
| 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles
164236
| 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte
165237
| 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines
166-
| QSPI_ADSIZE << QUADSPI_CCR_ADSIZE_Pos
238+
| adsize << QUADSPI_CCR_ADSIZE_Pos
167239
| 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines
168240
| 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
169-
| QSPI_CMD << QUADSPI_CCR_INSTRUCTION_Pos
241+
| cmd << QUADSPI_CCR_INSTRUCTION_Pos
170242
;
171243

172244
qspi_mpu_enable_mapped();
173245
}
174246

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) {
176248
(void)self_in;
177249
switch (cmd) {
178250
case MP_QSPI_IOCTL_INIT:
179-
qspi_init();
251+
qspi_init(0);
180252
break;
181253
case MP_QSPI_IOCTL_BUS_ACQUIRE:
182254
// Disable memory-mapped region during bus access
@@ -192,6 +264,11 @@ STATIC int qspi_ioctl(void *self_in, uint32_t cmd) {
192264
// Switch to memory-map mode when bus is idle
193265
qspi_memory_map();
194266
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;
195272
}
196273
return 0; // success
197274
}

ports/stm32/qspi.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
extern const mp_qspi_proto_t qspi_proto;
3232

33-
void qspi_init(void);
33+
void qspi_init(size_t memory_size_bytes);
3434
void qspi_memory_map(void);
3535

3636
#endif // MICROPY_INCLUDED_STM32_QSPI_H

0 commit comments

Comments
 (0)