Skip to content

Commit 3f09ce1

Browse files
committed
family/samx7x: implement internal flash methods
Signed-off-by: Rafael Silva <[email protected]>
1 parent 852bd3c commit 3f09ce1

File tree

3 files changed

+164
-12
lines changed

3 files changed

+164
-12
lines changed

src/platform/samx7x/eefc.c

+145-10
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,57 @@
55

66
#include <sam.h>
77

8+
#include "platform/samx7x/atomic.h"
89
#include "platform/samx7x/eefc.h"
910

10-
void eefc_config_waitstates(u32 frequency)
11+
#define ROM_BASE_ADDR 0x00400000ul
12+
13+
#define EEFC_ERROR_FLAGS \
14+
(EEFC_FSR_FLOCKE_Msk | EEFC_FSR_FCMDE_Msk | EEFC_FSR_FLERR_Msk | EEFC_FSR_UECCELSB_Msk | EEFC_FSR_MECCELSB_Msk | \
15+
EEFC_FSR_UECCEMSB_Msk | EEFC_FSR_MECCEMSB_Msk)
16+
17+
static struct flash_info_t flash_info;
18+
19+
/*
20+
* Local function declaration.
21+
* Because they are RAM functions, they need 'extern' declaration.
22+
*/
23+
extern void eefc_write_fmr(u32 fmr);
24+
extern u32 eefc_perform_fcr(u32 fcr);
25+
26+
static u32 eefc_get_result();
27+
static u32 eefc_get_status();
28+
static void eefc_perform_command(u32 command, u32 argument);
29+
30+
void eefc_init()
31+
{
32+
/* enable code loop optimization and sequential code optimization */
33+
eefc_write_fmr(EFC->EEFC_FMR & ~(EEFC_FMR_FWS_Msk | EEFC_FMR_SCOD_Msk) | EEFC_FMR_CLOE_Msk | EEFC_FMR_FWS(6));
34+
35+
eefc_perform_command(EEFC_FCR_FCMD_GETD, 0);
36+
while (!(eefc_get_status() & EEFC_FSR_FRDY_Msk)) continue;
37+
eefc_get_result(); /* dummy read: id */
38+
flash_info.size = eefc_get_result();
39+
flash_info.page_size = eefc_get_result();
40+
flash_info.base_addr = ROM_BASE_ADDR;
41+
}
42+
43+
void eefc_set_waitstates(u32 frequency)
1144
{
1245
if (frequency <= 23000000UL)
13-
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | (0 << EEFC_FMR_FWS_Pos);
46+
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(0);
1447
else if (frequency <= 46000000UL)
15-
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | (1 << EEFC_FMR_FWS_Pos);
48+
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(1);
1649
else if (frequency <= 69000000UL)
17-
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | (2 << EEFC_FMR_FWS_Pos);
50+
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(2);
1851
else if (frequency <= 92000000UL)
19-
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | (3 << EEFC_FMR_FWS_Pos);
52+
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(3);
2053
else if (frequency <= 115000000UL)
21-
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | (4 << EEFC_FMR_FWS_Pos);
54+
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(4);
2255
else if (frequency <= 138000000UL)
23-
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | (5 << EEFC_FMR_FWS_Pos);
56+
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(5);
2457
else
25-
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | (6 << EEFC_FMR_FWS_Pos);
58+
EFC->EEFC_FMR = (EFC->EEFC_FMR & ~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(6);
2659
}
2760

2861
void eefc_tcm_disable()
@@ -33,8 +66,110 @@ void eefc_tcm_disable()
3366

3467
__DSB();
3568
__ISB();
36-
SCB->ITCMCR &= ~(uint32_t) (1UL);
37-
SCB->DTCMCR &= ~(uint32_t) SCB_DTCMCR_EN_Msk;
69+
SCB->ITCMCR &= ~(u32) (1UL);
70+
SCB->DTCMCR &= ~(u32) SCB_DTCMCR_EN_Msk;
3871
__DSB();
3972
__ISB();
4073
}
74+
75+
const struct flash_info_t *eefc_get_info()
76+
{
77+
return (const struct flash_info_t *) &flash_info;
78+
}
79+
80+
s32 eefc_addr_to_page(u32 addr)
81+
{
82+
if (addr < flash_info.base_addr)
83+
return -1;
84+
85+
/* align to pages */
86+
addr -= (flash_info.base_addr);
87+
addr -= (addr % flash_info.page_size);
88+
89+
return (addr / flash_info.page_size);
90+
}
91+
92+
u32 eefc_page_to_addr(u32 page)
93+
{
94+
return ((page * flash_info.page_size) + flash_info.base_addr);
95+
}
96+
97+
u32 eefc_erase_16(u32 addr)
98+
{
99+
u32 page = eefc_addr_to_page(addr);
100+
101+
/* give erase and write page command */
102+
eefc_perform_command(EEFC_FCR_FCMD_EPA, (page & ~0xF) | 2); /* 16 pages (minimum for large sectors) */
103+
while (!(eefc_get_status() & EEFC_FSR_FRDY_Msk)) continue;
104+
}
105+
106+
void eefc_read(void *buffer, u32 addr, u32 size)
107+
{
108+
u8 *src = (u8 *) addr;
109+
u8 *dst = (u8 *) buffer;
110+
while (size--) {
111+
*dst++ = *src++;
112+
}
113+
}
114+
115+
void eefc_write(u32 addr, void *buffer, u32 size)
116+
{
117+
/* require 128 bit alignment, and single page writes */
118+
if ((addr % 16) || (size % 16) || ((size + (addr % 16)) > flash_info.page_size)) {
119+
return;
120+
}
121+
122+
size /= 4;
123+
u32 *dst = (u32 *) addr;
124+
u32 *src = (u32 *) buffer;
125+
while (size--) {
126+
*dst++ = *src++;
127+
}
128+
129+
u32 page = eefc_addr_to_page(addr);
130+
131+
/* give erase and write page command */
132+
eefc_perform_command(EEFC_FCR_FCMD_WP, page);
133+
while (!(eefc_get_status() & EEFC_FSR_FRDY_Msk)) continue;
134+
}
135+
136+
static u32 eefc_get_status()
137+
{
138+
return EFC->EEFC_FSR;
139+
}
140+
141+
static u32 eefc_get_result()
142+
{
143+
return EFC->EEFC_FRR;
144+
}
145+
146+
static void eefc_perform_command(u32 command, u32 argument)
147+
{
148+
/* Unique ID commands are not supported. */
149+
if (command == EEFC_FCR_FCMD_STUI || command == EEFC_FCR_FCMD_SPUI) {
150+
return;
151+
}
152+
153+
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
154+
{
155+
/* Use RAM Function. */
156+
eefc_perform_fcr(EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(argument) | EEFC_FCR_FCMD(command));
157+
}
158+
}
159+
160+
__attribute__((noinline, section(".ramfunc"))) void eefc_write_fmr(u32 fmr)
161+
{
162+
EFC->EEFC_FMR = fmr;
163+
}
164+
165+
__attribute__((noinline, section(".ramfunc"))) u32 eefc_perform_fcr(u32 fcr)
166+
{
167+
volatile u32 status;
168+
169+
EFC->EEFC_FCR = fcr;
170+
do {
171+
status = EFC->EEFC_FSR;
172+
} while (!(status & EEFC_FSR_FRDY_Msk));
173+
174+
return (status & EEFC_ERROR_FLAGS);
175+
}

src/platform/samx7x/eefc.h

+18-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,23 @@
99

1010
#include "util/types.h"
1111

12-
void eefc_config_waitstates(u32 frequency);
12+
struct flash_info_t {
13+
u32 base_addr;
14+
u32 size; /* Flash size in bytes */
15+
u32 page_size; /* Page size in bytes */
16+
};
17+
18+
void eefc_init();
19+
20+
void eefc_set_waitstates(u32 frequency);
1321

1422
void eefc_tcm_disable();
23+
24+
const struct flash_info_t *eefc_get_info();
25+
26+
s32 eefc_addr_to_page(u32 addr);
27+
u32 eefc_page_to_addr(u32 page);
28+
29+
u32 eefc_erase_16(u32 addr);
30+
void eefc_read(void *buffer, u32 addr, u32 size);
31+
void eefc_write(u32 addr, void *buffer, u32 size);

src/platform/samx7x/pmc.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ void pmc_init(u32 hfxo_freq, u32 lfxo_freq)
445445
pmc_clock_tree.lfrco_freq = 32000UL;
446446

447447
/* Configure flash waitstates */
448-
eefc_config_waitstates(150000000);
448+
eefc_set_waitstates(150000000);
449449

450450
pmc_osc_enable(OSC_MAINCK_XTAL);
451451

0 commit comments

Comments
 (0)