[rtems commit] mpc55xx/misc/flash_support.c: Properly flush cache when writing.

Joel Sherrill joel at rtems.org
Wed Aug 20 22:00:19 UTC 2014


Module:    rtems
Branch:    master
Commit:    dc661c87e1d8cda26330016976c4416805c65c7c
Changeset: http://git.rtems.org/rtems/commit/?id=dc661c87e1d8cda26330016976c4416805c65c7c

Author:    Peter Dufault <dufault at hda.com>
Date:      Wed Aug 20 17:08:23 2014 -0500

mpc55xx/misc/flash_support.c: Properly flush cache when writing.

    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) {



More information about the vc mailing list