Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
TiFlash.hxx
Go to the documentation of this file.
1
36#ifndef _FREERTOS_DRIVERS_TI_TIFLASH_HXX_
37#define _FREERTOS_DRIVERS_TI_TIFLASH_HXX_
38
39#ifdef TI_DUAL_BANK_FLASH
40
42#define FLASH_CONF 0x400FDFC8
45#define FCMME 0x40000000
48static const unsigned addr_mirror = (HWREG(FLASH_CONF) & FCMME) ? 0x80000 : 0;
49
50#else
51
52static constexpr unsigned addr_mirror = 0;
53
54#endif // Dual bank flash
55
56// Different options for what to set for flash write locking. These are only
57// needed to debug when the operating system is misbehaving during flash
58// writes.
59
60#if defined(TISPIFFS_LOCK_ALL_INTERRUPTS)
61
62// Global disable interrupts.
63
64#define DI() asm("cpsid i\n")
65#define EI() asm("cpsie i\n")
66
67#elif defined(TISPIFFS_LOCK_CRITICAL)
68
69// Critical section (interrupts better than MIN_SYSCALL_PRIORITY are still
70// running).
71
72#define DI() portENTER_CRITICAL()
73#define EI() portEXIT_CRITICAL()
74
75#elif defined(TISPIFFS_LOCK_BASEPRI_FF)
76
77// Disable interrupts with a priority limit of 0xFF (these are the lowest
78// priority interrupts, including the FreeRTOS kernel task switch interrupt).
79unsigned ppri;
80constexpr unsigned minpri = 0xFF;
81#define DI() \
82 do \
83 { \
84 unsigned r; \
85 __asm volatile(" mrs %0, basepri\n mov %1, %2\n msr basepri, %1\n" \
86 : "=r"(ppri), "=r"(r) \
87 : "i"(minpri) \
88 : "memory"); \
89 } while (0)
90#define EI() __asm volatile(" msr basepri, %0\n" : : "r"(ppri) : "memory")
91
92#elif defined(TISPIFFS_LOCK_NOTICK)
93
94// Disable the systick timer to prevent preemptive multi-tasking from changing
95// to a different task.
96
97static constexpr unsigned SYSTICKCFG = 0xE000E010;
98#define DI() HWREG(SYSTICKCFG) &= ~2;
99#define EI() HWREG(SYSTICKCFG) |= 2;
100
101#elif defined(TISPIFFS_LOCK_SCHEDULER_SUSPEND)
102
103// Disable freertos scheduler
104
105#define DI() vTaskSuspendAll()
106#define EI() xTaskResumeAll()
107
108#elif defined(TISPIFFS_LOCK_NONE)
109
110// No write locking.
111
112#define DI()
113#define EI()
114
115#elif defined(TISPIFFS_LOCK_CRASH)
116
117// Crashes if two different executions of this locking mechanism are
118// concurrent.
119
120unsigned pend = 0;
121#define DI() \
122 HASSERT(pend == 0); \
123 pend = 1;
124#define EI() pend = 0;
125
126#else
127#error Must specify what kind of locking to use for TISPIFFS.
128#endif
129
130// This ifdef decides whether we use the ROM or the flash based implementations
131// for Flash write and erase. It also supports correcting for the reversed bank
132// addresses.
133#if 1
134#define FPG(data, addr, size) ROM_FlashProgram(data, (addr) ^ addr_mirror, size)
135#define FER(addr) ROM_FlashErase((addr) ^ addr_mirror)
136#else
137#define FPG(data, addr, size) FlashProgram(data, (addr) ^ addr_mirror, size)
138#define FER(addr) FlashErase((addr) ^ addr_mirror)
139#endif
140
141template <uint32_t ERASE_PAGE_SIZE> class TiFlash
142{
143public:
144 constexpr TiFlash()
145 { }
146
152 static void write(uint32_t addr, const void *buf, uint32_t len)
153 {
154 // Theory of operation:
155 //
156 // The hardware has 32 word long write buffer. This is aligned based on
157 // the flash address that's being written. We split the writes on the
158 // boundary of this buffer (which is the low 7 bits of the address).
159 //
160 // For each buffer, we identify which words are touched by the
161 // write. We load these words (32 bits at a time), then we AND the data
162 // to be written into it (one byte at a time).
163 //
164 // Then we program from the buffer using the driverlib API.
165 //
166 // This algorithm is agnostic to the alignment of the actual writes,
167 // and we also guarantee that we never attempt to set a 0 bit to a 1
168 // bit in the flash. It also makes optimal use of the parallel write
169 // capability of the flash hardware.
170 static constexpr uint32_t BUF_WORD_LEN = 32;
171 static constexpr uint32_t BUF_BYTE_LEN = 128;
172 static constexpr uint32_t BUF_BYTE_MASK = BUF_BYTE_LEN - 1;
173 static constexpr uint32_t BYTE_PER_WORD = 4;
174 typedef union
175 {
176 uint32_t w[BUF_WORD_LEN];
177 uint8_t b[BUF_BYTE_LEN];
178 } BufType;
179 static BufType wrbuf;
180
181 const uint8_t *src = (const uint8_t *)buf;
182
183 while (len)
184 {
185 // memory address of the first byte in the buffer.
186 uint32_t *buf_address = (uint32_t *)(addr & ~BUF_BYTE_MASK);
187 // first word in the buffer that we need to program
188 uint32_t buf_word_ofs = (addr & BUF_BYTE_MASK) / BYTE_PER_WORD;
189 // first byte in the buffer that we need to load
190 uint32_t buf_byte_ofs = (addr & BUF_BYTE_MASK);
191 // how many bytes to copy to this buffer.
192 uint32_t buf_byte_count =
193 std::min((uint32_t)len, BUF_BYTE_LEN - buf_byte_ofs);
194 // first word that does not need to be touched
195 uint32_t buf_word_end =
196 (buf_byte_ofs + buf_byte_count + BYTE_PER_WORD - 1) /
197 BYTE_PER_WORD;
198 // how many words do we need to program.
199 uint32_t buf_word_count = buf_word_end - buf_word_ofs;
200
201 // Pre-fill data with existing flash content.
202 for (uint32_t i = 0; i < buf_word_count; ++i)
203 {
204 wrbuf.w[buf_word_ofs + i] = buf_address[buf_word_ofs + i];
205 }
206
207 // Copy the to-be-programmed data with AND operator.
208 for (uint32_t i = 0; i < buf_byte_count; ++i)
209 {
210 wrbuf.b[buf_byte_ofs + i] &= src[i];
211 }
212
213 // Program the buffer to flash.
214 DI();
215 HASSERT(FPG(wrbuf.w + buf_word_ofs,
216 ((uint32_t)buf_address) + buf_word_ofs * BYTE_PER_WORD,
217 buf_word_count * BYTE_PER_WORD) == 0);
218 EI();
219
220 // Go to the next flash buffer page.
221 len -= buf_byte_count;
222 addr += buf_byte_count;
223 src += buf_byte_count;
224 }
225 }
226
231 static void read(uint32_t addr, void *buf, size_t len)
232 {
233 memcpy(buf, (void *)addr, len);
234 }
235
241 static uint32_t next_sector_address(uint32_t addr)
242 {
243 return (addr + ERASE_PAGE_SIZE - 1) & ~(ERASE_PAGE_SIZE - 1);
244 }
245
249 static void erase(uint32_t addr, size_t len)
250 {
251 while (len)
252 {
253 DI();
254 HASSERT(FER(addr) == 0);
255 EI();
256 addr += ERASE_PAGE_SIZE;
257 len -= ERASE_PAGE_SIZE;
258 }
259 }
260};
261
262#undef DI
263#undef EI
264#undef FPG
265#undef FER
266
267#endif // _FREERTOS_DRIVERS_TI_TIFLASH_HXX_
static uint32_t next_sector_address(uint32_t addr)
Aligns an address to the next possible sector start (i.e., rounds up to sector boundary).
Definition TiFlash.hxx:241
static void read(uint32_t addr, void *buf, size_t len)
Reads data from the device.
Definition TiFlash.hxx:231
static void write(uint32_t addr, const void *buf, uint32_t len)
Performs write to the device.
Definition TiFlash.hxx:152
static void erase(uint32_t addr, size_t len)
Erases sector(s) of the device.
Definition TiFlash.hxx:249
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138