-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathflash.c
190 lines (155 loc) · 4.94 KB
/
flash.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include <stdint.h>
#include "flash.h"
#include "memio.h"
#include "kl17.h"
#ifndef NULL
#define NULL ((void *)0)
#endif
/* Commands */
#define FTFx_FSTAT_CCIF (1 << 7)
#define FTFx_FSTAT_RDCOLERR (1 << 6)
#define FTFx_FSTAT_ACCERR (1 << 5)
#define FTFx_FSTAT_FPVIOL (1 << 4)
#define FTFx_FSTAT_MGSTAT0 (1 << 0)
#define FTFx_CMD_BLOCKSTAT 0x00
#define FTFx_CMD_SECTSTAT 0x01
#define FTFx_CMD_PROGCHECK 0x02
#define FTFx_CMD_LWORDPROG 0x06
#define FTFx_CMD_SECTERASE 0x09
#define FTFx_CMD_SECTWRITE 0x0b
#define FTFx_CMD_MASSERASE 0x44
#define FTFx_CMD_PGMPART 0x80
#define FTFx_CMD_SETFLEXRAM 0x81
#define MAKE_FCCOB(a, b, c, d) ( \
(((a) << 24) & 0xff000000) | \
(((b) << 16) & 0x00ff0000) | \
(((c) << 8) & 0x0000ff00) | \
(((d) << 0) & 0x000000ff))
/* Uncomment this to store this function in RAM */
__attribute__((section(".ramtext"))) static int kinetis_flash_cmd(uint8_t cmd, uint32_t addr,
uint32_t data1, uint32_t data2,
void (*idle_func)(void))
{
uint8_t fstat;
int ret = F_ERR_OK;
/* Wait for (optional) previous command to complete */
while (!(readb(FTFx_FSTAT) & FTFx_FSTAT_CCIF))
;
/* Reset error flags, if present */
if (readb(FTFx_FSTAT) & (FTFx_FSTAT_ACCERR | FTFx_FSTAT_FPVIOL))
writeb(FTFx_FSTAT_ACCERR | FTFx_FSTAT_FPVIOL, FTFx_FSTAT);
/* Add in the command, which hangs out in the address top word */
addr &= 0xffffff;
addr |= (uint32_t)cmd << 24;
/* Load the command bytes */
writel(addr, FTFx_FCCOB3);
writel(data1, FTFx_FCCOB7);
writel(data2, FTFx_FCCOBB);
/* start command */
__disable_irq();
writeb(FTFx_FSTAT_CCIF, FTFx_FSTAT);
/* Wait for the command to complete */
while (!(readb(FTFx_FSTAT) & FTFx_FSTAT_CCIF))
{
if (idle_func)
idle_func();
}
fstat = readb(FTFx_FSTAT);
__enable_irq();
/* Check ACCERR and FPVIOL are zero in FSTAT */
if (fstat & (FTFx_FSTAT_ACCERR | FTFx_FSTAT_FPVIOL | FTFx_FSTAT_MGSTAT0))
ret = F_ERR_LOWLEVEL;
return ret;
}
// offset is in sectors
// sectorCount is in sectors
int8_t flashEraseSectors(uint32_t destination, uint16_t sectorCount, void (*idle_func)(void))
{
uint32_t end;
//uint16_t number; /* Number of longword or phrase to be program or verify*/
//uint32_t margin_read_level; /* 0=normal, 1=user - margin read for reading 1's */
int8_t retval = F_ERR_OK;
end = destination + (uint32_t)sectorCount;
if (end > ((P_FLASH_BASE + P_FLASH_SIZE) / FTFx_PSECTOR_SIZE))
{
retval = F_ERR_RANGE;
return retval;
}
while (destination < end)
{
retval = kinetis_flash_cmd(FTFx_CMD_SECTERASE,
destination * FTFx_PSECTOR_SIZE,
0, 0,
idle_func);
if (F_ERR_OK != retval)
return retval;
/*
for (margin_read_level = 0; margin_read_level <= 2; margin_read_level++) {
number = FTFx_PSECTOR_SIZE / 4;
retval = kinetis_flash_cmd(FTFx_CMD_SECTSTAT,
destination * FTFx_PSECTOR_SIZE,
MAKE_FCCOB(number >> 8, number, margin_read_level, 0),
0);
}
*/
destination++;
}
return retval;
}
void flashStart(void)
{
return;
}
uint32_t flashGetSecurity(void)
{
return readb(FTFx_FSEC) & 0x3;
}
// src, dst are pointers to physical memory locations, not sectors
// count is in bytes
int8_t flashProgram(uint8_t *src, uint8_t *dest, uint32_t count)
{
uint32_t ret = F_ERR_OK;
// uint32_t failaddr = 0;
uint32_t i;
// do nothing if our count is 0
if (count == 0)
return ret;
// check if dest, dest+count is in the user-designated area of FLASH
if (((uint32_t)dest + count) > (P_FLASH_BASE + P_FLASH_SIZE))
{
return F_ERR_RANGE;
}
// check if number of bytes to write, src, destination are word-aligned
if (((count % 4) != 0) || ((((uint32_t)dest) % 4) != 0) || ((((uint32_t)src) % 4) != 0))
return F_ERR_NOTALIGN;
// check that the destination bytes have been erased
// we can't re-program over 0's, it will overstress the Flash
// (per user manual spec)
for (i = 0; i < count; i++)
{
if (dest[i] != 0xFF)
return F_ERR_NOTBLANK;
}
for (i = 0; i < count; i += 4)
{
ret = kinetis_flash_cmd(FTFx_CMD_LWORDPROG,
(uint32_t)&dest[i],
*((uint32_t *)&src[i]), 0,
NULL);
}
if (ret)
return ret;
// user margin is more strict than normal margin -- data can be read still if
// this fails, but indicates flash is wearing out
for (i = 0; i < count; i += 4)
{
ret = kinetis_flash_cmd(FTFx_CMD_PROGCHECK,
(uint32_t)&dest[i],
MAKE_FCCOB(READ_USER_MARGIN, 0, 0, 0),
*((uint32_t *)&src[i]),
NULL);
}
if (ret)
return F_ERR_U_MARGIN;
return ret;
}