Skip to content

Commit e82f37c

Browse files
committed
enable cache in SAMD51
1 parent b0fba28 commit e82f37c

4 files changed

Lines changed: 85 additions & 5 deletions

File tree

ports/atmel-samd/external_flash/qspi_flash.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "mpconfigboard.h" // for EXTERNAL_FLASH_QSPI_DUAL
3333

3434
#include "external_flash/common_commands.h"
35+
#include "peripherals.h"
3536
#include "shared_dma.h"
3637

3738
#include "atmel_start_pins.h"
@@ -55,6 +56,8 @@ bool spi_flash_command(uint8_t command) {
5556
}
5657

5758
bool spi_flash_read_command(uint8_t command, uint8_t* response, uint32_t length) {
59+
samd_peripherals_disable_and_clear_cache();
60+
5861
QSPI->INSTRCTRL.bit.INSTR = command;
5962

6063
QSPI->INSTRFRAME.reg = QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI |
@@ -63,6 +66,11 @@ bool spi_flash_read_command(uint8_t command, uint8_t* response, uint32_t length)
6366
QSPI_INSTRFRAME_INSTREN |
6467
QSPI_INSTRFRAME_DATAEN;
6568

69+
// Dummy read of INSTRFRAME needed to synchronize.
70+
// See Instruction Transmission Flow Diagram, figure 37.9, page 995
71+
// and Example 4, page 998, section 37.6.8.5.
72+
(volatile uint32_t) QSPI->INSTRFRAME.reg;
73+
6674
memcpy(response, (uint8_t *) QSPI_AHB, length);
6775

6876
QSPI->CTRLA.reg = QSPI_CTRLA_ENABLE | QSPI_CTRLA_LASTXFER;
@@ -71,20 +79,28 @@ bool spi_flash_read_command(uint8_t command, uint8_t* response, uint32_t length)
7179

7280
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
7381

82+
samd_peripherals_enable_cache();
83+
7484
return true;
7585
}
7686

7787
bool spi_flash_write_command(uint8_t command, uint8_t* data, uint32_t length) {
88+
samd_peripherals_disable_and_clear_cache();
89+
7890
QSPI->INSTRCTRL.bit.INSTR = command;
7991

8092
QSPI->INSTRFRAME.reg = QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI |
8193
QSPI_INSTRFRAME_ADDRLEN_24BITS |
8294
QSPI_INSTRFRAME_TFRTYPE_WRITE |
83-
QSPI_INSTRFRAME_INSTREN;
95+
QSPI_INSTRFRAME_INSTREN |
96+
(data != NULL ? QSPI_INSTRFRAME_DATAEN : 0);
8497

85-
if (data != NULL) {
86-
QSPI->INSTRFRAME.bit.DATAEN = true;
98+
// Dummy read of INSTRFRAME needed to synchronize.
99+
// See Instruction Transmission Flow Diagram, figure 37.9, page 995
100+
// and Example 4, page 998, section 37.6.8.5.
101+
(volatile uint32_t) QSPI->INSTRFRAME.reg;
87102

103+
if (data != NULL) {
88104
memcpy((uint8_t *) QSPI_AHB, data, length);
89105
}
90106

@@ -94,6 +110,8 @@ bool spi_flash_write_command(uint8_t command, uint8_t* data, uint32_t length) {
94110

95111
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
96112

113+
samd_peripherals_enable_cache();
114+
97115
return true;
98116
}
99117

@@ -117,6 +135,8 @@ bool spi_flash_sector_command(uint8_t command, uint32_t address) {
117135
}
118136

119137
bool spi_flash_write_data(uint32_t address, uint8_t* data, uint32_t length) {
138+
samd_peripherals_disable_and_clear_cache();
139+
120140
QSPI->INSTRCTRL.bit.INSTR = CMD_PAGE_PROGRAM;
121141
uint32_t mode = QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI;
122142

@@ -137,10 +157,14 @@ bool spi_flash_write_data(uint32_t address, uint8_t* data, uint32_t length) {
137157

138158
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
139159

160+
samd_peripherals_enable_cache();
161+
140162
return true;
141163
}
142164

143165
bool spi_flash_read_data(uint32_t address, uint8_t* data, uint32_t length) {
166+
samd_peripherals_disable_and_clear_cache();
167+
144168
#ifdef EXTERNAL_FLASH_QSPI_DUAL
145169
QSPI->INSTRCTRL.bit.INSTR = CMD_DUAL_READ;
146170
uint32_t mode = QSPI_INSTRFRAME_WIDTH_DUAL_OUTPUT;
@@ -167,6 +191,8 @@ bool spi_flash_read_data(uint32_t address, uint8_t* data, uint32_t length) {
167191

168192
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
169193

194+
samd_peripherals_enable_cache();
195+
170196
return true;
171197
}
172198

@@ -183,7 +209,7 @@ void spi_flash_init(void) {
183209
// QSPI->BAUD.bit.BAUD = 32;
184210
// Super fast, may be unreliable when Saleae is connected to high speed lines.
185211
QSPI->BAUD.bit.BAUD = 2;
186-
QSPI->CTRLB.reg = QSPI_CTRLB_MODE_MEMORY |
212+
QSPI->CTRLB.reg = QSPI_CTRLB_MODE_MEMORY | // Serial memory mode (map to QSPI_AHB)
187213
QSPI_CTRLB_DATALEN_8BITS |
188214
QSPI_CTRLB_CSMODE_LASTXFER;
189215

ports/atmel-samd/samd51_peripherals.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,15 @@ void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance)
163163
hri_adc_write_CALIB_BIASR2R_bf(instance, biasr2r);
164164
hri_adc_write_CALIB_BIASCOMP_bf(instance, biascomp);
165165
}
166+
167+
// Turn off cache and invalidate all data in it.
168+
void samd_peripherals_disable_and_clear_cache(void) {
169+
CMCC->CTRL.bit.CEN = 0;
170+
while (CMCC->SR.bit.CSTS) {}
171+
CMCC->MAINT0.bit.INVALL = 1;
172+
}
173+
174+
// Enable cache
175+
void samd_peripherals_enable_cache(void) {
176+
CMCC->CTRL.bit.CEN = 1;
177+
}

ports/atmel-samd/samd51_peripherals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,7 @@ uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad);
3535
bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad);
3636
void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance);
3737

38+
void samd_peripherals_disable_and_clear_cache(void);
39+
void samd_peripherals_enable_cache(void);
40+
3841
#endif // MICROPY_INCLUDED_ATMEL_SAMD_SAMD51_PERIPHERALS_H

ports/atmel-samd/supervisor/port.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "shared-bindings/rtc/__init__.h"
5858
#include "clocks.h"
5959
#include "events.h"
60+
#include "peripherals.h"
6061
#include "shared_dma.h"
6162
#include "tick.h"
6263

@@ -105,9 +106,47 @@ safe_mode_t port_init(void) {
105106
SUPC->BOD33.bit.ENABLE = 0;
106107
SUPC->BOD33.bit.LEVEL = 200; // 2.7V: 1.5V + LEVEL * 6mV.
107108
SUPC->BOD33.bit.ENABLE = 1;
108-
#endif
109109

110+
// MPU (Memory Protection Unit) setup.
111+
// We hoped we could make the QSPI region be non-cachable with the MPU,
112+
// but the CMCC doesn't seem to pay attention to the MPU settings.
113+
// Leaving this code here disabled,
114+
// because it was hard enough to figure out, and maybe there's
115+
// a mistake that could make it work in the future.
116+
#if 0
117+
// Designate QSPI memory mapped region as not cachable.
118+
119+
// Turn off MPU in case it is on.
120+
MPU->CTRL = 0;
121+
// Configure region 0.
122+
MPU->RNR = 0;
123+
// Region base: start of QSPI mapping area.
124+
// QSPI region runs from 0x04000000 up to and not including 0x05000000: 16 megabytes
125+
MPU->RBAR = QSPI_AHB;
126+
MPU->RASR =
127+
0b011 << MPU_RASR_AP_Pos | // full read/write access for privileged and user mode
128+
0b000 << MPU_RASR_TEX_Pos | // caching not allowed, strongly ordered
129+
1 << MPU_RASR_S_Pos | // sharable
130+
0 << MPU_RASR_C_Pos | // not cachable
131+
0 << MPU_RASR_B_Pos | // not bufferable
132+
0b10111 << MPU_RASR_SIZE_Pos | // 16MB region size
133+
1 << MPU_RASR_ENABLE_Pos // enable this region
134+
;
135+
// Turn off regions 1-7.
136+
for (uint32_t i = 1; i < 8; i ++) {
137+
MPU->RNR = i;
138+
MPU->RBAR = 0;
139+
MPU->RASR = 0;
140+
}
110141

142+
// Turn on MPU. Turn on PRIVDEFENA, which defines a default memory
143+
// map for all privileged access, so we don't have to set up other regions
144+
// besides QSPI.
145+
MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
146+
#endif
147+
148+
samd_peripherals_enable_cache();
149+
#endif
111150

112151
// On power on start or external reset, set _ezero to the canary word. If it
113152
// gets killed, we boot in safe mode. _ezero is the boundary between statically

0 commit comments

Comments
 (0)