[PATCH] Properly flush cache when writing to MPC55XX flash.
Peter Dufault
dufault at hda.com
Wed Aug 20 20:48:06 UTC 2014
Also cleanup:
* Remove un-needed interrupt disables.
* Address errata "e989: FLASH: Disable Prefetch during programming and erase"
* Use RTEMS_ARRAY_SIZE() macro instead of own macro.
---
.../libcpu/powerpc/mpc55xx/misc/flash_support.c | 85 +++++++++-----------
1 files changed, 39 insertions(+), 46 deletions(-)
diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/misc/flash_support.c b/c/src/lib/libcpu/powerpc/mpc55xx/misc/flash_support.c
index 17c4e3f..b286b51 100644
--- a/c/src/lib/libcpu/powerpc/mpc55xx/misc/flash_support.c
+++ b/c/src/lib/libcpu/powerpc/mpc55xx/misc/flash_support.c
@@ -135,8 +135,6 @@ range_set(
*p_bits = bits;
}
-#define N(ARG) (sizeof(ARG)/sizeof(ARG[0]))
-
/** Return the size of the on-chip flash
* verifying that this is a device that we know about.
* @return 0 for OK, non-zero for error:
@@ -207,7 +205,6 @@ unlock_once(int lsel, int msel, int hbsel, int *p_locked)
union LMLR_tag lmlr;
union SLMLR_tag slmlr;
union HLR_tag hlr;
- rtems_interrupt_level level;
/* If we're already locked return.
*/
@@ -217,7 +214,6 @@ unlock_once(int lsel, int msel, int hbsel, int *p_locked)
/* Do we have to lock something in the low or mid block?
*/
- rtems_interrupt_disable(level);
lmlr = FLASH.LMLR;
if ((lsel || msel) && (lmlr.B.LME == 0)) {
union LMLR_tag lmlr_unlock;
@@ -228,7 +224,6 @@ unlock_once(int lsel, int msel, int hbsel, int *p_locked)
if (lmlr.B.LLOCK != lmlr_unlock.B.LLOCK ||
lmlr.B.MLOCK != lmlr_unlock.B.MLOCK) {
if (p_locked == 0) {
- rtems_interrupt_enable(level);
return MPC55XX_FLASH_LOCK_ERR;
} else {
*p_locked = 1;
@@ -237,9 +232,7 @@ unlock_once(int lsel, int msel, int hbsel, int *p_locked)
FLASH.LMLR = lmlr_unlock;
}
}
- rtems_interrupt_enable(level);
- rtems_interrupt_disable(level);
slmlr = FLASH.SLMLR;
if ((lsel || msel) && (slmlr.B.SLE == 0)) {
union SLMLR_tag slmlr_unlock;
@@ -250,7 +243,6 @@ unlock_once(int lsel, int msel, int hbsel, int *p_locked)
if (slmlr.B.SLLOCK != slmlr_unlock.B.SLLOCK ||
slmlr.B.SMLOCK != slmlr_unlock.B.SMLOCK) {
if (p_locked == 0) {
- rtems_interrupt_enable(level);
return MPC55XX_FLASH_LOCK_ERR;
} else {
*p_locked = 1;
@@ -259,11 +251,9 @@ unlock_once(int lsel, int msel, int hbsel, int *p_locked)
FLASH.SLMLR = slmlr_unlock;
}
}
- rtems_interrupt_enable(level);
/* Do we have to unlock something in the high block?
*/
- rtems_interrupt_disable(level);
hlr = FLASH.HLR;
if (hbsel && (hlr.B.HBE == 0)) {
union HLR_tag hlr_unlock;
@@ -272,7 +262,6 @@ unlock_once(int lsel, int msel, int hbsel, int *p_locked)
if (hlr.B.HBLOCK != hlr_unlock.B.HBLOCK) {
if (p_locked == 0) {
return MPC55XX_FLASH_LOCK_ERR;
- rtems_interrupt_enable(level);
} else {
*p_locked = 1;
}
@@ -280,7 +269,6 @@ unlock_once(int lsel, int msel, int hbsel, int *p_locked)
FLASH.HLR = hlr_unlock;
}
}
- rtems_interrupt_enable(level);
return 0;
}
@@ -398,24 +386,25 @@ mpc55xx_flash_copy_op(
{
uint32_t udest, usrc, flash_size;
int r;
- int peg; /* Program or Erase Good - Did it work? */
+ int peg; /* Program or Erase Good - Did it work? */
- int lsel; /* Low block select bits. */
- int msel; /* Mid block select bits. */
- int hbsel; /* High block select bits. */
+ int lsel; /* Low block select bits. */
+ int msel; /* Mid block select bits. */
+ int hbsel; /* High block select bits. */
- int s_lsel; /* Source Low block select bits. */
- int s_msel; /* Source Mid block select bits. */
- int s_hbsel; /* Source High block select bits. */
+ int s_lsel; /* Source Low block select bits. */
+ int s_msel; /* Source Mid block select bits. */
+ int s_hbsel; /* Source High block select bits. */
int unlocked = 0;
int *p_unlocked;
int i;
- int nwords; /* The number of 32 bit words to write. */
- volatile uint32_t *flash; /* Where the flash is mapped in. */
- volatile uint32_t *memory; /* What to copy into flash. */
- uint32_t offset; /* Where the FLASH is mapped into memory. */
- rtems_interrupt_level level;
+ int nwords; /* The number of 32 bit words to write. */
+ volatile uint32_t *flash; /* Where the flash is mapped in. */
+ volatile uint32_t *memory; /* What to copy into flash. */
+ const void *flashing_from; /* Where we are flahsing from.
+ * "const" is to match invalidate cache function signature. */
+ uint32_t offset; /* Where the FLASH is mapped into memory. */
if ( (r = mpc55xx_flash_size(&flash_size))) {
return r;
@@ -461,13 +450,13 @@ mpc55xx_flash_copy_op(
/* Set up the bit masks for the blocks to program or erase.
*/
- range_set(udest, udest + nbytes, &lsel, lsel_ranges, N( lsel_ranges));
- range_set(udest, udest + nbytes, &msel, msel_ranges, N( msel_ranges));
- range_set(udest, udest + nbytes, &hbsel, hbsel_ranges, N(hbsel_ranges));
+ range_set(udest, udest + nbytes, &lsel, lsel_ranges, RTEMS_ARRAY_SIZE( lsel_ranges));
+ range_set(udest, udest + nbytes, &msel, msel_ranges, RTEMS_ARRAY_SIZE( msel_ranges));
+ range_set(udest, udest + nbytes, &hbsel, hbsel_ranges, RTEMS_ARRAY_SIZE(hbsel_ranges));
- range_set(usrc, usrc + nbytes, &s_lsel, lsel_ranges, N( lsel_ranges));
- range_set(usrc, usrc + nbytes, &s_msel, msel_ranges, N( msel_ranges));
- range_set(usrc, usrc + nbytes, &s_hbsel, hbsel_ranges, N(hbsel_ranges));
+ range_set(usrc, usrc + nbytes, &s_lsel, lsel_ranges, RTEMS_ARRAY_SIZE( lsel_ranges));
+ range_set(usrc, usrc + nbytes, &s_msel, msel_ranges, RTEMS_ARRAY_SIZE( msel_ranges));
+ range_set(usrc, usrc + nbytes, &s_hbsel, hbsel_ranges, RTEMS_ARRAY_SIZE(hbsel_ranges));
/* Are we attempting overlapping flash?
*/
@@ -481,33 +470,39 @@ mpc55xx_flash_copy_op(
/* In the following sections any "Step N" notes refer to
* the steps in "13.4.2.3 Flash Programming" in the reference manual.
- * XXX Do parts of this neeed to be protected by interrupt locks?
*/
if (opmask & MPC55XX_FLASH_ERASE) { /* Erase. */
+ uint32_t flash_biucr_r;
if ( (r = unlock_once(lsel, msel, hbsel, p_unlocked)) ) {
return r;
}
- rtems_interrupt_disable(level);
+ /* Per errata "e989: FLASH: Disable Prefetch during programming and erase" */
+ flash_biucr_r = FLASH.BIUCR.R;
+ FLASH.BIUCR.B.PFLIM = 0;
+
+ FLASH.MCR.B.ESUS = 0; /* Be sure ESUS is clear. */
+
FLASH.MCR.B.ERS = 1; /* Step 1: Select erase. */
FLASH.LMSR.B.LSEL = lsel; /* Step 2: Select blocks to be erased. */
FLASH.LMSR.B.MSEL = msel;
FLASH.HSR.B.HBSEL = hbsel;
- flash[0] = 1; /* Step 3: Write to any address in the flash
+ flash[0] = 0xffffffff; /* Step 3: Write to any address in the flash
* (the "erase interlock write)".
*/
+ rtems_cache_flush_multiple_data_lines(flash, sizeof(flash[0]));
+
FLASH.MCR.B.EHV = 1; /* Step 4: Enable high V to start erase. */
- rtems_interrupt_enable(level);
while (FLASH.MCR.B.DONE == 0) { /* Step 5: Wait until done. */
}
- rtems_interrupt_disable(level);
peg = FLASH.MCR.B.PEG; /* Save result. */
FLASH.MCR.B.EHV = 0; /* Disable high voltage. */
FLASH.MCR.B.ERS = 0; /* De-select erase. */
- rtems_interrupt_enable(level);
+ FLASH.BIUCR.R = flash_biucr_r;
+
if (peg == 0) {
return MPC55XX_FLASH_ERASE_ERR; /* Flash erase failed. */
}
@@ -534,9 +529,7 @@ mpc55xx_flash_copy_op(
}
FLASH.MCR.B.PGM = 1; /* Step 1 */
- rtems_interrupt_disable(level);
-
- for (i = 0; i < nwords; i += 2) {
+ for (flashing_from = (const void *)flash, i = 0; i < nwords; i += 2) {
flash[i] = memory[i]; /* Step 2 */
flash[i + 1] = memory[i + 1]; /* Always program in min 64 bits. */
@@ -548,45 +541,45 @@ mpc55xx_flash_copy_op(
chunk++;
if (chunk == 4) {
/* Collected 4 64-bits for a 256 bit chunk. */
+
+ rtems_cache_flush_multiple_data_lines(flashing_from, 32); /* Flush cache. */
+
FLASH.MCR.B.EHV = 1; /* Step 4: Enable high V. */
- rtems_interrupt_enable(level);
while (FLASH.MCR.B.DONE == 0) { /* Step 5: Wait until done. */
}
- rtems_interrupt_disable(level);
peg = FLASH.MCR.B.PEG; /* Step 6: Save result. */
FLASH.MCR.B.EHV = 0; /* Step 7: Disable high V. */
if (peg == 0) {
FLASH.MCR.B.PGM = 0;
- rtems_interrupt_enable(level);
if (p_fail) {
*p_fail = (uint32_t)(flash + i);
}
return MPC55XX_FLASH_PROGRAM_ERR; /* Programming failed. */
}
chunk = 0; /* Reset chunk counter. */
+ flashing_from = (const void *)(flash + i);
}
/* Step 8: Back to step 2. */
}
if (!chunk) {
FLASH.MCR.B.PGM = 0;
- rtems_interrupt_enable(level);
} else {
/* If there is anything left in that last chunk flush it out:
*/
+
+ rtems_cache_flush_multiple_data_lines(flashing_from, chunk * 8);
+
FLASH.MCR.B.EHV = 1;
- rtems_interrupt_enable(level);
while (FLASH.MCR.B.DONE == 0) { /* Wait until done. */
}
- rtems_interrupt_disable(level);
peg = FLASH.MCR.B.PEG; /* Save result. */
FLASH.MCR.B.EHV = 0; /* Disable high voltage. */
FLASH.MCR.B.PGM = 0;
- rtems_interrupt_enable(level);
if (peg == 0) {
if (p_fail) {
--
1.7.1
More information about the devel
mailing list