Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:56

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSBSPsPowerPCMPC55XX
0005  *
0006  *  @brief MPC55XX flash memory support.
0007  *
0008  *  I set my MMU up to map what will finally be in flash into RAM and at the
0009  *  same time I map the flash to a different location.  When the software
0010  *  is tested I can use this to copy the RAM version of the program into
0011  *  the flash and when I reboot I'm running out of flash.
0012  *
0013  *  I use a flag word located after the boot configuration half-word to
0014  *  indicate that the MMU should be left alone, and I don't include the RCHW
0015  *  or that flag in my call to this routine.
0016  *
0017  *  There are obviously other uses for this.
0018  **/
0019 
0020 /*
0021  * Copyright (c) 2009-2011
0022  * HD Associates, Inc.
0023  * 18 Main Street
0024  * Pepperell, MA 01463
0025  * USA
0026  * dufault@hda.com
0027  *
0028  * The license and distribution terms for this file may be
0029  * found in the file LICENSE in this distribution or at
0030  * http://www.rtems.org/license/LICENSE.
0031  */
0032 
0033 #include <errno.h>
0034 #include <sys/types.h>
0035 #include <mpc55xx/regs.h>
0036 #include <mpc55xx/mpc55xx.h>
0037 
0038 #include <libcpu/powerpc-utility.h>
0039 #include <rtems/powerpc/registers.h>
0040 
0041 #if MPC55XX_CHIP_FAMILY == 555 || MPC55XX_CHIP_FAMILY == 556
0042 
0043 /* Set up the memory ranges for the flash on
0044  * the MPC5553, MPC5554, MPC5566 and MPC5567.
0045  * I check if it is an unknown CPU and return an error.
0046  *
0047  * These CPUS have a low, mid, and high space of memory.
0048  *
0049  * Only the low space really needs a table like this, but for simplicity
0050  * I do low, mid, and high the same way.
0051  */
0052 struct range {          /* A memory range. */
0053     uint32_t lower;
0054     uint32_t upper;
0055 };
0056 
0057 /* The ranges of the memory banks for the low space.  All the
0058  * chips I'm looking at share this low format, identified by LAS=6:
0059  * 2 16K banks,
0060  * 2 48K banks,
0061  * 2 64K banks.
0062  */
0063 static const struct range lsel_ranges[] = {
0064     {                        0, (1*16              )*1024 - 1},
0065     {(1*16              )*1024, (2*16              )*1024 - 1},
0066     {(2*16              )*1024, (2*16 + 1*48       )*1024 - 1},
0067     {(2*16 + 1*48       )*1024, (2*16 + 2*48       )*1024 - 1},
0068     {(2*16 + 2*48       )*1024, (2*16 + 2*48 + 1*64)*1024 - 1},
0069     {(2*16 + 2*48 + 1*64)*1024, (2*16 + 2*48 + 2*64)*1024 - 1},
0070 };
0071 
0072 /* The ranges of the memory blocks for the mid banks, 2 128K banks.
0073  * Again, all the chips share this, identified by MAS=0.
0074  */
0075 #define MBSTART ((2*16+2*48+2*64)*1024)
0076 static const struct range msel_ranges[] = {
0077     {MBSTART             , MBSTART + 1*128*1024 - 1},
0078     {MBSTART + 1*128*1024, MBSTART + 2*128*1024 - 1},
0079 };
0080 
0081 /* The ranges of the memory blocks for the high banks.
0082  * There are N 128K banks, where N <= 20,
0083  * and is identified by looking at the SIZE field.
0084  *
0085  * This could benefit from being redone to save a few bytes
0086  * and provide for bigger flash spaces.
0087  */
0088 #define HBSTART (MBSTART+2*128*1024)
0089 static const struct range hbsel_ranges[] = {
0090     {HBSTART              , HBSTART +  1*128*1024 - 1},
0091     {HBSTART +  1*128*1024, HBSTART +  2*128*1024 - 1},
0092     {HBSTART +  2*128*1024, HBSTART +  3*128*1024 - 1},
0093     {HBSTART +  3*128*1024, HBSTART +  4*128*1024 - 1},
0094     {HBSTART +  4*128*1024, HBSTART +  5*128*1024 - 1},
0095     {HBSTART +  5*128*1024, HBSTART +  6*128*1024 - 1},
0096     {HBSTART +  6*128*1024, HBSTART +  7*128*1024 - 1},
0097     {HBSTART +  7*128*1024, HBSTART +  8*128*1024 - 1},
0098     {HBSTART +  8*128*1024, HBSTART +  9*128*1024 - 1},
0099     {HBSTART +  9*128*1024, HBSTART + 10*128*1024 - 1},
0100     {HBSTART + 10*128*1024, HBSTART + 11*128*1024 - 1},
0101     {HBSTART + 11*128*1024, HBSTART + 12*128*1024 - 1},
0102     {HBSTART + 12*128*1024, HBSTART + 13*128*1024 - 1},
0103     {HBSTART + 13*128*1024, HBSTART + 14*128*1024 - 1},
0104     {HBSTART + 14*128*1024, HBSTART + 15*128*1024 - 1},
0105     {HBSTART + 15*128*1024, HBSTART + 16*128*1024 - 1},
0106     {HBSTART + 16*128*1024, HBSTART + 17*128*1024 - 1},
0107     {HBSTART + 17*128*1024, HBSTART + 18*128*1024 - 1},
0108     {HBSTART + 18*128*1024, HBSTART + 19*128*1024 - 1},
0109     {HBSTART + 19*128*1024, HBSTART + 20*128*1024 - 1},
0110 };
0111 
0112 /* Set bits in a bitmask to indicate which banks are
0113  * within the range "first" and "last".
0114  */
0115 static void
0116 range_set(
0117   uint32_t first,
0118   uint32_t last,
0119   int *p_bits,
0120   const struct range *pr,
0121   int n_range
0122 )
0123 {
0124     int i;
0125     int bits = 0;
0126     for (i = 0; i < n_range; i++) {
0127         /* If the upper limit is less than "first" or the lower limit
0128          * is greater than "last" then the block is not in range.
0129          */
0130         if ( !(pr[i].upper < first || pr[i].lower > last)) {
0131             bits |= (1 << i);   /* This block is in the range, set the bit. */
0132         }
0133 
0134     }
0135     *p_bits = bits;
0136 }
0137 
0138 /** Return the size of the on-chip flash
0139  *  verifying that this is a device that we know about.
0140  * @return 0 for OK, non-zero for error:
0141  *  - MPC55XX_FLASH_VERIFY_ERR for LAS not 6 or MAS not 0.
0142  *    @note This is overriding what verify means!
0143  *  - MPC55XX_FLASH_SIZE_ERR Not a chip I've checked against the manual,
0144  *                           athat is, SIZE not 5, 7, or 11.
0145  */
0146 int
0147 mpc55xx_flash_size(
0148   uint32_t *p_size  /**< The size is returned here. */
0149 )
0150 {
0151     /* On the MPC5553, MPC5554, MPC5566, and MP5567 the
0152      *  low address space LAS field is 0x6 and all have
0153      *  six blocks sized 2*16k, 2*48k, and 2*64k.
0154      *
0155      * All the mid and high address spaces have 128K blocks.
0156      *
0157      * The mid address space MAS size field is 0 for the above machines,
0158      * and they all have 2 128K blocks.
0159      *
0160      * For the high address space we look at the
0161      * size field to figure out the size.  The SIZE field is:
0162      *
0163      * 5 for 1.5MB (MPC5553)
0164      * 7 for 2MB (MPC5554, MPC5567)
0165      * 11 for 3MB  (MPC5566)
0166      */
0167     int hblocks;    /* The number of blocks in the high address space. */
0168 
0169     /* Verify the configuration matches one of the chips that I've checked out.
0170      */
0171     if (FLASH.MCR.B.LAS != 6 || FLASH.MCR.B.MAS != 0) {
0172         return MPC55XX_FLASH_VERIFY_ERR;
0173     }
0174 
0175     switch(FLASH.MCR.B.SIZE) {
0176         case 5:
0177         hblocks = 8;
0178         break;
0179 
0180         case 7:
0181         hblocks = 12;
0182         break;
0183 
0184         case 11:
0185         hblocks = 20;
0186         break;
0187 
0188         default:
0189         return MPC55XX_FLASH_SIZE_ERR;
0190     }
0191 
0192     /* The first two banks are 256K.
0193      * The high block has "hblocks" 128K blocks.
0194      */
0195     *p_size = 256*1024 + 256*1024 + hblocks * 128*1024;
0196     return 0;
0197 }
0198 
0199 /* Unlock the flash blocks if "p_locked" points to something that is 0.
0200  * If it is a NULL pointer then we aren't allowed to do the unlock.
0201  */
0202 static int
0203 unlock_once(int lsel, int msel, int hbsel, int *p_locked)
0204 {
0205     union LMLR_tag lmlr;
0206     union SLMLR_tag slmlr;
0207     union HLR_tag hlr;
0208 
0209     /* If we're already locked return.
0210      */
0211     if (p_locked && (*p_locked == 1)) {
0212         return 0;
0213     }
0214 
0215     /* Do we have to lock something in the low or mid block?
0216      */
0217     lmlr = FLASH.LMLR;
0218     if ((lsel || msel) && (lmlr.B.LME == 0)) {
0219         union LMLR_tag lmlr_unlock;
0220         lmlr_unlock.B.LLOCK=~lsel;
0221         lmlr_unlock.B.MLOCK=~msel;
0222         lmlr_unlock.B.SLOCK=1;
0223 
0224         if (lmlr.B.LLOCK != lmlr_unlock.B.LLOCK ||
0225         lmlr.B.MLOCK != lmlr_unlock.B.MLOCK) {
0226             if (p_locked == 0) {
0227                 return MPC55XX_FLASH_LOCK_ERR;
0228             } else {
0229                 *p_locked = 1;
0230             }
0231             FLASH.LMLR.R = 0xA1A11111;  /* Unlock. */
0232             FLASH.LMLR = lmlr_unlock;
0233         }
0234     }
0235 
0236     slmlr = FLASH.SLMLR;
0237     if ((lsel || msel) && (slmlr.B.SLE == 0)) {
0238         union SLMLR_tag slmlr_unlock;
0239         slmlr_unlock.B.SLLOCK=~lsel;
0240         slmlr_unlock.B.SMLOCK=~msel;
0241         slmlr_unlock.B.SSLOCK=1;
0242 
0243         if (slmlr.B.SLLOCK != slmlr_unlock.B.SLLOCK ||
0244         slmlr.B.SMLOCK != slmlr_unlock.B.SMLOCK) {
0245             if (p_locked == 0) {
0246                 return MPC55XX_FLASH_LOCK_ERR;
0247             } else {
0248                 *p_locked = 1;
0249             }
0250             FLASH.SLMLR.R = 0xC3C33333;  /* Unlock. */
0251             FLASH.SLMLR = slmlr_unlock;
0252         }
0253     }
0254 
0255     /* Do we have to unlock something in the high block?
0256      */
0257     hlr = FLASH.HLR;
0258     if (hbsel && (hlr.B.HBE == 0)) {
0259         union HLR_tag hlr_unlock;
0260         hlr_unlock.B.HBLOCK = ~hbsel;
0261 
0262         if (hlr.B.HBLOCK != hlr_unlock.B.HBLOCK) {
0263             if (p_locked == 0) {
0264                 return MPC55XX_FLASH_LOCK_ERR;
0265             } else {
0266                 *p_locked = 1;
0267             }
0268             FLASH.HLR.R = 0xB2B22222;   /* Unlock. */
0269             FLASH.HLR = hlr_unlock;
0270         }
0271     }
0272 
0273     return 0;
0274 }
0275 
0276 static inline uint32_t
0277 tsize(int i)
0278 {
0279   return 1 << (10 + 2 * i);
0280 }
0281 
0282 static int
0283 addr_map(
0284   int to_phys,         /* If 1 lookup physical else lookup mapped. */
0285   const void *addr,    /* The address to look up. */
0286   uint32_t *p_result   /* Result is here. */
0287 )
0288 {
0289     uint32_t u_addr = (uint32_t)addr;
0290     uint32_t mas0, mas1, mas2, mas3;
0291     uint32_t start, end;
0292     rtems_interrupt_level level;
0293     int i;
0294 
0295     for (i = 0; i < 32; i++) {
0296       mas0 = 0x10000000 | (i << 16);
0297       rtems_interrupt_disable(level);
0298       PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS0, mas0);
0299       asm volatile("tlbre");
0300       PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS1, mas1);
0301       PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS2, mas2);
0302       PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3, mas3);
0303       rtems_interrupt_enable(level);
0304 
0305       if (mas1 & 0x80000000) {
0306         /* Valid. */
0307         start = (to_phys ? mas2 : mas3) & 0xFFFFF000;
0308         end = start + tsize((mas1 >> 8) & 0x0000000F);
0309         /* Are we within range?
0310          */
0311         if (start <= u_addr && end >= u_addr) {
0312           uint32_t offset = (to_phys ? mas3 : mas2) & 0xFFFFF000;
0313           *p_result = u_addr - offset;
0314           return 0;
0315         }
0316       }
0317     }
0318 
0319     /* Not found in a TLB.
0320      */
0321     return ESRCH;
0322 }
0323 
0324 /** Return the physical address corresponding to a mapped address.
0325   @return 0 if OK, ESRCH if not found in TLB1.
0326  **/
0327 int
0328 mpc55xx_physical_address(
0329   const void *addr,     /**< Mapped address. */
0330   uint32_t *p_result    /**< Result returned here. */
0331 )
0332 {
0333     return addr_map(1, addr, p_result);
0334 }
0335 
0336 /** Return the mapped address corresponding to a mapped address.
0337   @return 0 if OK, ESRCH if not found in TLB1.
0338  **/
0339 int
0340 mpc55xx_mapped_address(
0341   const void *addr,     /**< Mapped address. */
0342   uint32_t *p_result    /**< Result returned here. */
0343 )
0344 {
0345     return addr_map(0, addr, p_result);
0346 }
0347 
0348 /**
0349  * Copy memory from an address into the flash when flash is relocated
0350  * If programming fails the address that it failed at can be returned.
0351  @note At end of operation the flash may be left writable.
0352  *     Use mpc55xx_flash_read_only() to set read-only.
0353  @return Zero for OK, non-zero for error:
0354  * - ESRCH                       Can't lookup where something lives.
0355  * - EPERM                       Attempt to write to non-writable flash.
0356  * - ETXTBSY                     Attempt to flash overlapping regions.
0357  * - MPC55XX_FLASH_CONFIG_ERR    for LAS not 6 or MAS not 0.
0358  * - MPC55XX_FLASH_SIZE_ERR      for SIZE not 5, 7, or 11.
0359  * - MPC55XX_FLASH_RANGE_ERR     for illegal access:
0360  *                               - first or first+last outside of flash;
0361  *                               - first not on a mod(8) boundary;
0362  *                               - nbytes not multiple of 8.
0363  * - MPC55XX_FLASH_ERASE_ERR     Erase requested but failed.
0364  * - MPC55XX_FLASH_PROGRAM_ERR   Program requested but failed.
0365  * - MPC55XX_FLASH_NOT_BLANK_ERR Blank check requested but not blank.
0366  * - MPC55XX_FLASH_VERIFY_ERR    Verify requested but failed.
0367  * - MPC55XX_FLASH_LOCK_ERR      Unlock requested but failed.
0368  **/
0369 
0370 int
0371 mpc55xx_flash_copy_op(
0372   void *dest,       /**< An address in the flash to copy to. */
0373   const void *src,  /**< An address in memory to copy from. */
0374   size_t nbytes,    /**< The number of bytes to copy. */
0375   uint32_t opmask,  /**< Bitmask of operations to perform.
0376                      * - MPC55XX_FLASH_UNLOCK:      Unlock the blocks.
0377                      * - MPC55XX_FLASH_ERASE:       Erase the blocks.
0378                      * - MPC55XX_FLASH_BLANK_CHECK: Verify the blocks are blank.
0379                      * - MPC55XX_FLASH_PROGRAM:     Program the FLASH.
0380                      * - MPC55XX_FLASH_VERIFY:      Verify the regions match.
0381                      **/
0382   uint32_t *p_fail  /**< If not NULL then the address where the operation
0383                      *   failed is returned here.
0384                      **/
0385 )
0386 {
0387     uint32_t udest, usrc, flash_size;
0388     int r;
0389     int peg;                        /* Program or Erase Good - Did it work? */
0390 
0391     int lsel;                       /* Low block select bits. */
0392     int msel;                       /* Mid block select bits. */
0393     int hbsel;                      /* High block select bits. */
0394 
0395     int s_lsel;                     /* Source Low block select bits. */
0396     int s_msel;                     /* Source Mid block select bits. */
0397     int s_hbsel;                    /* Source High block select bits. */
0398 
0399     int unlocked = 0;
0400     int *p_unlocked;
0401     int i;
0402     int nwords;                     /* The number of 32 bit words to write. */
0403     volatile uint32_t *flash;       /* Where the flash is mapped in. */
0404     volatile uint32_t *memory;      /* What to copy into flash. */
0405     const void *flashing_from;      /* Where we are flahsing from.
0406                                      * "const" is to match invalidate cache function signature. */
0407     uint32_t offset;                /* Where the FLASH is mapped into memory. */
0408 
0409     if ( (r = mpc55xx_flash_size(&flash_size))) {
0410         return r;
0411     }
0412 
0413     /* Get where the flash is mapped in.
0414      */
0415     offset = mpc55xx_flash_address();
0416 
0417     udest = ((uint32_t)dest) - offset;
0418     if ( (r = mpc55xx_physical_address(src, &usrc)) ) {
0419       return r;
0420     }
0421 
0422     /* Verify that the address being programmed is in flash and that it is
0423      * a multiple of 64 bits.
0424      * Someone else can remove the 64-bit restriction.
0425      */
0426     if (udest > flash_size ||
0427     udest + nbytes > flash_size ||
0428     (udest & 0x7) != 0 ||
0429     (nbytes & 0x7) != 0) {
0430         return MPC55XX_FLASH_RANGE_ERR;
0431     }
0432 
0433     if (opmask == 0) {
0434         return 0;
0435     }
0436 
0437     /* If we're going to do a write-style operation the flash must be writable.
0438      */
0439     if ((opmask &
0440         (MPC55XX_FLASH_UNLOCK | MPC55XX_FLASH_ERASE | MPC55XX_FLASH_PROGRAM)) &&
0441         !mpc55xx_flash_writable()
0442     ) {
0443       return EPERM;
0444     }
0445 
0446     /* If we aren't allowed to unlock then set the pointer to zero.
0447      * That is how "unlock_once" decides we can't unlock.
0448      */
0449     p_unlocked = (opmask & MPC55XX_FLASH_UNLOCK) ? &unlocked : 0;
0450 
0451     /* Set up the bit masks for the blocks to program or erase.
0452      */
0453     range_set(udest, udest + nbytes, &lsel,   lsel_ranges, RTEMS_ARRAY_SIZE( lsel_ranges));
0454     range_set(udest, udest + nbytes, &msel,   msel_ranges, RTEMS_ARRAY_SIZE( msel_ranges));
0455     range_set(udest, udest + nbytes, &hbsel, hbsel_ranges, RTEMS_ARRAY_SIZE(hbsel_ranges));
0456 
0457     range_set(usrc, usrc + nbytes, &s_lsel,   lsel_ranges, RTEMS_ARRAY_SIZE( lsel_ranges));
0458     range_set(usrc, usrc + nbytes, &s_msel,   msel_ranges, RTEMS_ARRAY_SIZE( msel_ranges));
0459     range_set(usrc, usrc + nbytes, &s_hbsel, hbsel_ranges, RTEMS_ARRAY_SIZE(hbsel_ranges));
0460 
0461     /* Are we attempting overlapping flash?
0462      */
0463     if ((lsel & s_lsel) | (msel & s_msel) | (hbsel & s_hbsel)) {
0464       return ETXTBSY;
0465     }
0466 
0467     nwords = nbytes / 4;
0468     flash = (volatile uint32_t *)dest;
0469     memory = (volatile uint32_t *)src;
0470 
0471   /* In the following sections any "Step N" notes refer to
0472    * the steps in "13.4.2.3 Flash Programming" in the reference manual.
0473    */
0474 
0475     if (opmask & MPC55XX_FLASH_ERASE) {   /* Erase. */
0476         uint32_t flash_biucr_r;
0477         if ( (r = unlock_once(lsel, msel, hbsel, p_unlocked)) ) {
0478             return r;
0479         }
0480 
0481         /* Per errata "e989: FLASH: Disable Prefetch during programming and erase" */
0482         flash_biucr_r = FLASH.BIUCR.R;
0483         FLASH.BIUCR.B.PFLIM = 0;
0484 
0485         FLASH.MCR.B.ESUS = 0;       /* Be sure ESUS is clear. */
0486 
0487         FLASH.MCR.B.ERS = 1;        /* Step 1: Select erase. */
0488 
0489         FLASH.LMSR.B.LSEL = lsel;   /* Step 2: Select blocks to be erased. */
0490         FLASH.LMSR.B.MSEL = msel;
0491         FLASH.HSR.B.HBSEL = hbsel;
0492 
0493         flash[0] = 0xffffffff;      /* Step 3: Write to any address in the flash
0494                                      * (the "erase interlock write)".
0495                                      */
0496         rtems_cache_flush_multiple_data_lines(
0497           RTEMS_DEVOLATILE(void *,flash),
0498           sizeof(flash[0])
0499         );
0500 
0501         FLASH.MCR.B.EHV = 1;         /* Step 4: Enable high V to start erase. */
0502         while (FLASH.MCR.B.DONE == 0) { /* Step 5: Wait until done. */
0503         }
0504         peg = FLASH.MCR.B.PEG;       /* Save result. */
0505         FLASH.MCR.B.EHV = 0;         /* Disable high voltage. */
0506         FLASH.MCR.B.ERS = 0;         /* De-select erase. */
0507         FLASH.BIUCR.R = flash_biucr_r;
0508 
0509         if (peg == 0) {
0510             return MPC55XX_FLASH_ERASE_ERR; /* Flash erase failed. */
0511         }
0512     }
0513 
0514     if (opmask & MPC55XX_FLASH_BLANK_CHECK) {    /* Verify blank. */
0515         for (i = 0; i < nwords; i++) {
0516            if (flash[i] != 0xffffffff) {
0517                 if (p_fail) {
0518                     *p_fail = (uint32_t)(flash + i);
0519                 }
0520                 return MPC55XX_FLASH_NOT_BLANK_ERR; /* Not blank. */
0521            }
0522         }
0523     }
0524 
0525   /* Program.
0526    */
0527     if (opmask & MPC55XX_FLASH_PROGRAM) {
0528         int chunk = 0;  /* Used to collect programming into 256 bit chunks. */
0529 
0530         if ( (r = unlock_once(lsel, msel, hbsel, p_unlocked)) ) {
0531             return r;
0532         }
0533         FLASH.MCR.B.PGM = 1;                /* Step 1 */
0534 
0535         for (flashing_from = (const void *)flash, i = 0; i < nwords; i += 2) {
0536            flash[i] = memory[i];            /* Step 2 */
0537            flash[i + 1] = memory[i + 1];    /* Always program in min 64 bits. */
0538 
0539           /* Step 3 is "write additional words" */
0540 
0541            /* Try to program in chunks of 256 bits.
0542             * Collect the 64 bit writes into 256 bit ones:
0543             */
0544            chunk++;
0545            if (chunk == 4) {
0546                 /* Collected 4 64-bits for a 256 bit chunk. */
0547 
0548                 rtems_cache_flush_multiple_data_lines(flashing_from, 32);    /* Flush cache. */
0549 
0550                 FLASH.MCR.B.EHV = 1;            /* Step 4: Enable high V. */
0551 
0552                 while (FLASH.MCR.B.DONE == 0) { /* Step 5: Wait until done. */
0553                 }
0554 
0555                 peg = FLASH.MCR.B.PEG;          /* Step 6: Save result. */
0556                 FLASH.MCR.B.EHV = 0;            /* Step 7: Disable high V. */
0557                 if (peg == 0) {
0558                     FLASH.MCR.B.PGM = 0;
0559                     if (p_fail) {
0560                         *p_fail = (uint32_t)(flash + i);
0561                     }
0562                     return MPC55XX_FLASH_PROGRAM_ERR; /* Programming failed. */
0563                 }
0564                 chunk = 0;                       /* Reset chunk counter. */
0565                 flashing_from = (const void *)(flash + i);
0566             }
0567                                                  /* Step 8: Back to step 2. */
0568         }
0569 
0570        if (!chunk) {
0571             FLASH.MCR.B.PGM = 0;
0572        } else {
0573            /* If there is anything left in that last chunk flush it out:
0574             */
0575 
0576             rtems_cache_flush_multiple_data_lines(flashing_from, chunk * 8);
0577 
0578             FLASH.MCR.B.EHV = 1;
0579 
0580             while (FLASH.MCR.B.DONE == 0) {     /* Wait until done. */
0581             }
0582 
0583             peg = FLASH.MCR.B.PEG;              /* Save result. */
0584             FLASH.MCR.B.EHV = 0;                /* Disable high voltage. */
0585             FLASH.MCR.B.PGM = 0;
0586 
0587             if (peg == 0) {
0588                 if (p_fail) {
0589                     *p_fail = (uint32_t)(flash + i);
0590                 }
0591                 return MPC55XX_FLASH_PROGRAM_ERR; /* Programming failed. */
0592             }
0593         }
0594     }
0595 
0596     if (opmask & MPC55XX_FLASH_VERIFY) {        /* Verify memory matches. */
0597         for (i = 0; i < nwords; i++) {
0598            if (flash[i] != memory[i]) {
0599                 if (p_fail) {              /* Return the failed address. */
0600                     *p_fail = (uint32_t)(flash + i);
0601                 }
0602                 return MPC55XX_FLASH_VERIFY_ERR; /* Verification failed. */
0603            }
0604         }
0605     }
0606 
0607     return 0;
0608 }
0609 
0610 /** Simple flash copy with a signature that matches memcpy.
0611  @note At end of operation the flash may be left writable.
0612  *     Use mpc55xx_flash_read_only() to set read-only.
0613  @return Zero for OK, non-zero for error.
0614  *       see flash_copy_op() for possible errors.
0615  **/
0616 int
0617 mpc55xx_flash_copy(
0618   void *dest,       /**< An address in the flash to copy to. */
0619   const void *src,  /**< An address in the flash copy from. */
0620   size_t nbytes     /**< The number of bytes to copy. */
0621 )
0622 {
0623     return mpc55xx_flash_copy_op(dest, src, nbytes,
0624         (MPC55XX_FLASH_UNLOCK      |
0625          MPC55XX_FLASH_ERASE       |
0626          MPC55XX_FLASH_BLANK_CHECK |
0627          MPC55XX_FLASH_PROGRAM     |
0628          MPC55XX_FLASH_VERIFY      ), 0);
0629 }
0630 
0631 /** Make the flash read-write.
0632  @note This assumes the flash is mapped by TLB1 entry 1.
0633  */
0634 void
0635 mpc55xx_flash_set_read_write(void)
0636 {
0637     rtems_interrupt_level level;
0638     rtems_interrupt_disable(level);
0639     PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
0640     asm volatile("tlbre");
0641     PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(FSL_EIS_MAS3, 0x0000000C);
0642     asm volatile("tlbwe");
0643     rtems_interrupt_enable(level);
0644 }
0645 
0646 /** Make the flash read-only.
0647  @note This assumes the flash is mapped by TLB1 entry 1.
0648  */
0649 void
0650 mpc55xx_flash_set_read_only(void)
0651 {
0652     rtems_interrupt_level level;
0653     rtems_interrupt_disable(level);
0654     PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
0655     asm volatile("tlbre");
0656     PPC_CLEAR_SPECIAL_PURPOSE_REGISTER_BITS(FSL_EIS_MAS3, 0x0000000C);
0657     asm volatile("tlbwe");
0658     rtems_interrupt_enable(level);
0659 }
0660 
0661 /** See if the flash is writable.
0662  *  @note This assumes the flash is mapped by TLB1 entry 1.
0663  *  @note It needs to be writable by both user and supervisor.
0664  */
0665 int
0666 mpc55xx_flash_writable(void)
0667 {
0668     uint32_t mas3;
0669     rtems_interrupt_level level;
0670 
0671     rtems_interrupt_disable(level);
0672     PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
0673     asm volatile("tlbre");
0674     PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3, mas3);
0675     rtems_interrupt_enable(level);
0676 
0677     return ((mas3 & 0x0000000C) == 0x0000000C) ? 1 : 0;
0678 }
0679 
0680 /** Return the address where the flash is mapped in.
0681  @note This assumes the flash is mapped by TLB1 entry 1.
0682  **/
0683 uint32_t
0684 mpc55xx_flash_address(void)
0685 {
0686     uint32_t mas2;
0687     rtems_interrupt_level level;
0688 
0689     rtems_interrupt_disable(level);
0690     PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
0691     asm volatile("tlbre");
0692     PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS2, mas2);
0693     rtems_interrupt_enable(level);
0694 
0695     return mas2 & 0xFFFFF000;
0696 }
0697 
0698 #endif /* MPC55XX_CHIP_FAMILY == 555 || MPC55XX_CHIP_FAMILY == 556 */