@@ -146,6 +146,102 @@ extern volatile uint32_t *const kFCCOBx;
146
146
#define SIZEOF_DOUBLE_PHRASE (16)
147
147
#endif /* #ifdef USING_KSDK2 */
148
148
149
+ /* While the K64F flash controller is capable of launching operations asynchronously and
150
+ * allowing program execution to continue while an erase/program is active, it
151
+ * doesn't allow simultaneous read accesses while and erase/program is active on
152
+ * the same block of flash.
153
+ *
154
+ * Read/fetch accesses can originate arbitrarily as a result of program
155
+ * execution. This means that code which operates on flash should not reside in
156
+ * flash; or at least it should not reside in the same bank of flash as it is
157
+ * operating upon. The only way to ensure that application code and flash driver
158
+ * are residing on separate banks of flash is to reserve bank-0 (or BLOCK0) for
159
+ * the application and bank-1 (BLOCK1) for the driver--this also happens to be
160
+ * the default setting.
161
+ *
162
+ * But it is quite likely that this default will be over-ridden by the use of
163
+ * config options depending upon the actual application. If we don't have a
164
+ * clean separation between the application and the space managed by this
165
+ * driver, then we need to enforce the following:
166
+ *
167
+ * - Force synchronous mode of execution in the storage_driver.
168
+ * - Disable interrupts during erase/program operations.
169
+ * - Ensure all code and data structures used in the storage driver execute
170
+ * out of RAM. Refer to __RAMFUNC (below) which allows for this.
171
+ *
172
+ * It is difficult to determine the application's span of internal-flash at
173
+ * compile time. Therefore we assume that CONFIG_HARDWARE_MTD_START_ADDR is the
174
+ * boundary between application and this driver. When this boundary is set to
175
+ * lie at BLOCK1_START_ADDR, there is no possibility of read-while-write run-
176
+ * time errors.
177
+ *
178
+ * In the following, caps.asynchronous_ops is defined to be 1 if and only if
179
+ * asynchronous operation mode is requested and there doesn't exist the
180
+ * possibility of concurrent reads.
181
+ */
182
+
183
+ #if (defined(CONFIG_HARDWARE_MTD_START_ADDR ) && (CONFIG_HARDWARE_MTD_START_ADDR != BLOCK1_START_ADDR ))
184
+ #define EXISTS_POSSIBILITY_OF_CONCURRENT_READ 1
185
+ #else
186
+ #define EXISTS_POSSIBILITY_OF_CONCURRENT_READ 0
187
+ #endif
188
+
189
+ /* Define '__RAMFUNC' as an attribute to mark a function as residing in RAM. */
190
+ #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
191
+ #if defined(__GNUC__ ) || defined (__CC_ARM ) || defined(__clang__ ) // GCC, armcc and llvm/clang
192
+ #ifndef __RAMFUNC
193
+ /* define __RAMFUNC to put a declaration in the .data section--i.e. the
194
+ * initialized data section. This will be copied into RAM automatically by the
195
+ * startup sequence. */
196
+ #define __RAMFUNC __attribute__ ((section (".data#"))) /* The '#' following ".data" needs a bit of
197
+ * explanation. Without it, we are liable to get the following warning 'Warning: ignoring
198
+ * changed section attributes for .data'. This is because __attribute__((section(".data")))
199
+ * generates the following assembly:
200
+ *
201
+ * .section .data,"ax",%progbits
202
+ *
203
+ * But .data doesn't need the 'x' (execute) attribute bit. To remove the warning, we specify
204
+ * the attribute with a '#' at the tail, which emits:
205
+ *
206
+ * .section .data#,"ax",%progbits
207
+ *
208
+ * Note that '#' (in the above) acts like a comment-start, and masks the additional
209
+ * attributes which don't apply to '.data'.
210
+ */
211
+ #endif /* #ifndef __RAMFUNC */
212
+ #elif defined ( __ICCARM__ )
213
+ #ifndef __RAMFUNC
214
+ #define __RAMFUNC __ramfunc
215
+ #endif
216
+ #else // unknown compiler
217
+ #error "This compiler is not yet supported. If you can contribute support for defining a function to be RAM resident, please provide a definition for __RAMFUNC"
218
+ #endif
219
+
220
+ /**
221
+ * @brief RAM resident memcpy.
222
+ *
223
+ * If we require all functions involved in the erase and programming of flash to
224
+ * be memory-resident (see the explanations around __RAMFUNC above), then we
225
+ * need to provide our own version of memcpy().
226
+ *
227
+ * @Note 'n' should be a multiple of sizeof(uint32_t).
228
+ */
229
+ __RAMFUNC
230
+ static void MEMCPY (void * _dest , const void * _src , size_t n )
231
+ {
232
+ uint32_t * dest = _dest ;
233
+ const uint32_t * src = _src ;
234
+ while (n ) {
235
+ * dest ++ = * src ++ ;
236
+ n -= sizeof (uint32_t );
237
+ }
238
+ }
239
+
240
+ #else /* #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ */
241
+ #define __RAMFUNC /* empty */
242
+ #define MEMCPY memcpy
243
+ #endif /* #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ */
244
+
149
245
150
246
/*
151
247
* forward declarations
@@ -205,7 +301,8 @@ static const ARM_DRIVER_VERSION version = {
205
301
};
206
302
207
303
208
- #if (!defined(CONFIG_HARDWARE_MTD_ASYNC_OPS ) || CONFIG_HARDWARE_MTD_ASYNC_OPS )
304
+ #if ((!defined(CONFIG_HARDWARE_MTD_ASYNC_OPS ) || CONFIG_HARDWARE_MTD_ASYNC_OPS ) && \
305
+ !EXISTS_POSSIBILITY_OF_CONCURRENT_READ )
209
306
#define ASYNC_OPS 1
210
307
#else
211
308
#define ASYNC_OPS 0
@@ -278,6 +375,7 @@ enum FlashCommandOps {
278
375
* Read out the CCIF (Command Complete Interrupt Flag) to ensure all previous
279
376
* operations have completed.
280
377
*/
378
+ __RAMFUNC
281
379
static inline bool controllerCurrentlyBusy (void )
282
380
{
283
381
#ifdef USING_KSDK2
@@ -287,6 +385,7 @@ static inline bool controllerCurrentlyBusy(void)
287
385
#endif
288
386
}
289
387
388
+ __RAMFUNC
290
389
static inline bool failedWithAccessError (void )
291
390
{
292
391
#ifdef USING_KSDK2
@@ -300,6 +399,7 @@ static inline bool failedWithAccessError(void)
300
399
#endif /* ifdef USING_KSDK2 */
301
400
}
302
401
402
+ __RAMFUNC
303
403
static inline bool failedWithProtectionError ()
304
404
{
305
405
#ifdef USING_KSDK2
@@ -313,6 +413,7 @@ static inline bool failedWithProtectionError()
313
413
#endif /* ifdef USING_KSDK2 */
314
414
}
315
415
416
+ __RAMFUNC
316
417
static inline bool failedWithRunTimeError ()
317
418
{
318
419
#ifdef USING_KSDK2
@@ -326,6 +427,7 @@ static inline bool failedWithRunTimeError()
326
427
#endif /* ifdef USING_KSDK2 */
327
428
}
328
429
430
+ __RAMFUNC
329
431
static inline void clearAccessError (void )
330
432
{
331
433
#ifdef USING_KSDK2
@@ -335,6 +437,7 @@ static inline void clearAccessError(void)
335
437
#endif
336
438
}
337
439
440
+ __RAMFUNC
338
441
static inline void clearProtectionError (void )
339
442
{
340
443
#ifdef USING_KSDK2
@@ -359,6 +462,7 @@ static inline void clearProtectionError(void)
359
462
* be cleared to launch a command. The FPVIOL bit is cleared by writing a 1 to
360
463
* it.
361
464
*/
465
+ __RAMFUNC
362
466
static inline void clearErrorStatusBits ()
363
467
{
364
468
if (failedWithAccessError ()) {
@@ -369,6 +473,7 @@ static inline void clearErrorStatusBits()
369
473
}
370
474
}
371
475
476
+ __RAMFUNC
372
477
static inline void enableCommandCompletionInterrupt (void )
373
478
{
374
479
#ifdef USING_KSDK2
@@ -378,6 +483,7 @@ static inline void enableCommandCompletionInterrupt(void)
378
483
#endif
379
484
}
380
485
486
+ __RAMFUNC
381
487
static inline void disbleCommandCompletionInterrupt (void )
382
488
{
383
489
#ifdef USING_KSDK2
@@ -387,6 +493,7 @@ static inline void disbleCommandCompletionInterrupt(void)
387
493
#endif
388
494
}
389
495
496
+ __RAMFUNC
390
497
static inline bool commandCompletionInterruptEnabled (void )
391
498
{
392
499
#ifdef USING_KSDK2
@@ -401,6 +508,7 @@ static inline bool commandCompletionInterruptEnabled(void)
401
508
* command by clearing the FSTAT[CCIF] bit by writing a '1' to it. The CCIF flag
402
509
* remains zero until the FTFE command completes.
403
510
*/
511
+ __RAMFUNC
404
512
static inline void launchCommand (void )
405
513
{
406
514
#ifdef USING_KSDK2
@@ -411,6 +519,7 @@ static inline void launchCommand(void)
411
519
}
412
520
413
521
#ifndef USING_KSDK2
522
+ __RAMFUNC
414
523
static inline void setupAddressInCCOB123 (uint64_t addr )
415
524
{
416
525
BW_FTFE_FCCOB1_CCOBn ((uintptr_t )FTFE , (addr >> 16 ) & 0xFFUL ); /* bits [23:16] of the address. */
@@ -419,6 +528,7 @@ static inline void setupAddressInCCOB123(uint64_t addr)
419
528
}
420
529
#endif /* ifndef USING_KSDK2 */
421
530
531
+ __RAMFUNC
422
532
static inline void setupEraseSector (uint64_t addr )
423
533
{
424
534
#ifdef USING_KSDK2
@@ -429,6 +539,7 @@ static inline void setupEraseSector(uint64_t addr)
429
539
#endif
430
540
}
431
541
542
+ __RAMFUNC
432
543
static inline void setupEraseBlock (uint64_t addr )
433
544
{
434
545
#ifdef USING_KSDK2
@@ -439,6 +550,7 @@ static inline void setupEraseBlock(uint64_t addr)
439
550
#endif
440
551
}
441
552
553
+ __RAMFUNC
442
554
static inline void setup8ByteWrite (uint64_t addr , const void * data )
443
555
{
444
556
/* Program FCCOB to load the required command parameters. */
@@ -463,17 +575,18 @@ static inline void setup8ByteWrite(uint64_t addr, const void *data)
463
575
#endif /* ifdef USING_KSDK2 */
464
576
}
465
577
578
+ __RAMFUNC
466
579
static inline void setupProgramSection (uint64_t addr , const void * data , size_t cnt )
467
580
{
468
581
#ifdef USING_KSDK2
469
582
static const uintptr_t FlexRAMBase = FSL_FEATURE_FLASH_FLEX_RAM_START_ADDRESS ;
470
- memcpy ((void * )FlexRAMBase , (const uint8_t * )data , cnt );
583
+ MEMCPY ((void * )FlexRAMBase , (const uint8_t * )data , cnt );
471
584
472
585
kFCCOBx [0 ] = BYTES_JOIN_TO_WORD_1_3 (PGMSEC , addr );
473
586
kFCCOBx [1 ] = BYTES_JOIN_TO_WORD_2_2 (cnt >> 4 , 0xFFFFU );
474
587
#else /* ifdef USING_KSDK2 */
475
588
static const uintptr_t FlexRAMBase = 0x14000000 ;
476
- memcpy ((void * )FlexRAMBase , (const uint8_t * )data , cnt );
589
+ MEMCPY ((void * )FlexRAMBase , (const uint8_t * )data , cnt );
477
590
478
591
BW_FTFE_FCCOB0_CCOBn ((uintptr_t )FTFE , PGMSEC );
479
592
setupAddressInCCOB123 (addr );
@@ -489,6 +602,7 @@ static inline void setupProgramSection(uint64_t addr, const void *data, size_t c
489
602
* that 'addr' is aligned to a double-phrase boundary (see \ref
490
603
* SIZEOF_DOUBLE_PHRASE)--if not, then only a single phrase (8-bytes) write is possible.
491
604
*/
605
+ __RAMFUNC
492
606
static inline size_t sizeofLargestProgramSection (uint64_t addr , size_t size )
493
607
{
494
608
/* ensure 'size' is aligned to a double-phrase boundary */
@@ -514,6 +628,7 @@ static inline size_t sizeofLargestProgramSection(uint64_t addr, size_t size)
514
628
* Advance the state machine for program-data. This function is called only if
515
629
* amountLeftToOperate is non-zero.
516
630
*/
631
+ __RAMFUNC
517
632
static inline void setupNextProgramData (struct mtd_k64f_data * context )
518
633
{
519
634
if ((context -> amountLeftToOperate == PROGRAM_PHRASE_SIZEOF_INLINE_DATA ) ||
@@ -537,6 +652,7 @@ static inline void setupNextProgramData(struct mtd_k64f_data *context)
537
652
* Advance the state machine for erase. This function is called only if
538
653
* amountLeftToOperate is non-zero.
539
654
*/
655
+ __RAMFUNC
540
656
static inline void setupNextErase (struct mtd_k64f_data * context )
541
657
{
542
658
setupEraseSector (context -> currentOperatingStorageAddress ); /* Program FCCOB to load the required command parameters. */
@@ -545,10 +661,19 @@ static inline void setupNextErase(struct mtd_k64f_data *context)
545
661
context -> currentOperatingStorageAddress += ERASE_UNIT ;
546
662
}
547
663
664
+ __RAMFUNC
548
665
static int32_t executeCommand (struct mtd_k64f_data * context )
549
666
{
667
+ #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
668
+ __disable_irq ();
669
+ #endif
550
670
launchCommand ();
551
671
672
+ /* !Note!: After launching the command, we should be very careful not to execute any
673
+ * code which might access the flash concurrent to the ongoing operation.
674
+ * Any code that needs to run in parallel should be executed from RAM (see __RAMFUNC).
675
+ * Interrupts should be disabled except when executing asynchronously. */
676
+
552
677
/* At this point, The FTFE reads the command code and performs a series of
553
678
* parameter checks and protection checks, if applicable, which are unique
554
679
* to each command. */
@@ -569,7 +694,7 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
569
694
570
695
return ARM_DRIVER_OK ; /* signal asynchronous completion. An interrupt will signal completion later. */
571
696
#else /* #if ASYNC_OPS */
572
- /* Synchronous operation. */
697
+ /* Synchronous operation. This is the common case. */
573
698
574
699
while (1 ) {
575
700
/* Spin waiting for the command execution to complete. */
@@ -578,19 +703,43 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
578
703
/* Execution may result in failure. Check for errors */
579
704
if (failedWithAccessError () || failedWithProtectionError ()) {
580
705
clearErrorStatusBits ();
706
+ #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
707
+ __enable_irq ();
708
+ #endif
581
709
return ARM_DRIVER_ERROR_PARAMETER ;
582
710
}
583
711
if (failedWithRunTimeError ()) {
712
+ #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
713
+ __enable_irq ();
714
+ #endif
584
715
return ARM_DRIVER_ERROR ; /* unspecified runtime error. */
585
716
}
586
717
587
718
/* signal synchronous completion. */
588
719
switch (context -> currentCommand ) {
589
720
case ARM_STORAGE_OPERATION_PROGRAM_DATA :
590
721
if (context -> amountLeftToOperate == 0 ) {
722
+ #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
723
+ __enable_irq ();
724
+ #endif
591
725
return context -> sizeofCurrentOperation ;
592
726
}
593
727
728
+ /* Allow pending interrupts to be handled before launching the successive
729
+ * operation. This avoids having to block interrupts for long periods.
730
+ *
731
+ * ProgramData operates in steps of 1KB; initial experiments
732
+ * indicate that the time needed to complete a 1KB write is
733
+ * around 6.5ms. As a programData progresses, interrupts would
734
+ * need to be held blocked for periods of such duration
735
+ * if EXISTS_POSSIBILITY_OF_CONCURRENT_READ.
736
+ */
737
+ #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
738
+ __enable_irq ();
739
+ /* service any pending interrupts at this moment */
740
+ __disable_irq ();
741
+ #endif
742
+
594
743
/* start the successive program operation */
595
744
setupNextProgramData (context );
596
745
launchCommand ();
@@ -599,15 +748,36 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
599
748
600
749
case ARM_STORAGE_OPERATION_ERASE :
601
750
if (context -> amountLeftToOperate == 0 ) {
751
+ #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
752
+ __enable_irq ();
753
+ #endif
602
754
return context -> sizeofCurrentOperation ;
603
755
}
604
756
757
+ /* Allow pending interrupts to be handled before launching the successive
758
+ * operation. This avoids having to block interrupts for long periods.
759
+ *
760
+ * Erase operates in steps of 4KB (ERASE_UNIT); initial
761
+ * experiments indicate that the time needed to complete a 4KB
762
+ * erase is around 4ms. As an erase progresses, interrupts
763
+ * would need to be held blocked for periods of such duration
764
+ * if EXISTS_POSSIBILITY_OF_CONCURRENT_READ.
765
+ */
766
+ #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
767
+ __enable_irq ();
768
+ /* service any pending interrupts at this moment */
769
+ __disable_irq ();
770
+ #endif
771
+
605
772
setupNextErase (context ); /* start the successive erase operation */
606
773
launchCommand ();
607
774
/* continue on to the next iteration of the parent loop */
608
775
break ;
609
776
610
777
default :
778
+ #if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
779
+ __enable_irq ();
780
+ #endif
611
781
return 1 ;
612
782
}
613
783
}
0 commit comments