source: rtems/c/src/lib/libcpu/powerpc/mpc55xx/misc/flash_support.c @ c1188b41

4.115
Last change on this file since c1188b41 was c1188b41, checked in by Sebastian Huber <sebastian.huber@…>, on 08/30/11 at 13:30:09

2011-08-30 Peter Dufault <dufault@…>

  • mpc55xx/misc/flash_support.c: New file.
  • Makefile.am: Reflect change above.
  • mpc55xx/include/mpc55xx.h: Add definitions for the FLASH interface and two memory protect interfaces. Add modifications to eliminate warnings in some of the cache macros.
  • mpc55xx/include/regs.h: Add some structure tag names for some structures that I needed access to. Don't define the ALTCADR for the MPC5554 - it is reserved and acess casues an exception. Hide the C99 designated initializers when compiling with C++. Add some support for the EQADC.
  • mpc55xx/include/esci.h, mpc55xx/include/watchdog.h: Add C++ protection.
  • Property mode set to 100644
File size: 22.2 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup mpc55xx
5 *
6 *  @brief MPC55XX flash memory support.
7 *
8 *  I set my MMU up to map what will finally be in flash into RAM and at the
9 *  same time I map the flash to a different location.  When the software
10 *  is tested I can use this to copy the RAM version of the program into
11 *  the flash and when I reboot I'm running out of flash.
12 *
13 *  I use a flag word located after the boot configuration half-word to
14 *  indicate that the MMU should be left alone, and I don't include the RCHW
15 *  or that flag in my call to this routine.
16 *
17 *  There are obviously other uses for this.
18 **/
19
20/*
21 * Copyright (c) 2009-2011
22 * HD Associates, Inc.
23 * 18 Main Street
24 * Pepperell, MA 01463
25 * USA
26 * dufault@hda.com
27 *
28 * The license and distribution terms for this file may be found in the file
29 * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE.
30 */
31
32#include <errno.h>
33#include <sys/types.h>
34#include <mpc55xx/regs.h>
35#include <mpc55xx/mpc55xx.h>
36
37#include <libcpu/powerpc-utility.h>
38#include <rtems/powerpc/registers.h>
39
40/* Set up the memory ranges for the flash on
41 * the MPC5553, MPC5554, MPC5566 and MPC5567.
42 * I check if it is an unknown CPU and return an error.
43 *
44 * These CPUS have a low, mid, and high space of memory.
45 *
46 * Only the low space really needs a table like this, but for simplicity
47 * I do low, mid, and high the same way.
48 */
49struct range {          /* A memory range. */
50    uint32_t lower;
51    uint32_t upper;
52};
53
54/* The ranges of the memory banks for the low space.  All the
55 * chips I'm looking at share this low format, identified by LAS=6:
56 * 2 16K banks,
57 * 2 48K banks,
58 * 2 64K banks.
59 */
60static const struct range lsel_ranges[] = {
61    {                        0, (1*16              )*1024 - 1},
62    {(1*16              )*1024, (2*16              )*1024 - 1},
63    {(2*16              )*1024, (2*16 + 1*48       )*1024 - 1},
64    {(2*16 + 1*48       )*1024, (2*16 + 2*48       )*1024 - 1},
65    {(2*16 + 2*48       )*1024, (2*16 + 2*48 + 1*64)*1024 - 1},
66    {(2*16 + 2*48 + 1*64)*1024, (2*16 + 2*48 + 2*64)*1024 - 1},
67};
68
69/* The ranges of the memory blocks for the mid banks, 2 128K banks.
70 * Again, all the chips share this, identified by MAS=0.
71 */
72#define MBSTART ((2*16+2*48+2*64)*1024)
73static const struct range msel_ranges[] = {
74    {MBSTART             , MBSTART + 1*128*1024 - 1},
75    {MBSTART + 1*128*1024, MBSTART + 2*128*1024 - 1},
76};
77
78/* The ranges of the memory blocks for the high banks.
79 * There are N 128K banks, where N <= 20,
80 * and is identified by looking at the SIZE field.
81 *
82 * This could benefit from being redone to save a few bytes
83 * and provide for bigger flash spaces.
84 */
85#define HBSTART (MBSTART+2*128*1024)
86static const struct range hbsel_ranges[] = {
87    {HBSTART              , HBSTART +  1*128*1024 - 1},
88    {HBSTART +  1*128*1024, HBSTART +  2*128*1024 - 1},
89    {HBSTART +  2*128*1024, HBSTART +  3*128*1024 - 1},
90    {HBSTART +  3*128*1024, HBSTART +  4*128*1024 - 1},
91    {HBSTART +  4*128*1024, HBSTART +  5*128*1024 - 1},
92    {HBSTART +  5*128*1024, HBSTART +  6*128*1024 - 1},
93    {HBSTART +  6*128*1024, HBSTART +  7*128*1024 - 1},
94    {HBSTART +  7*128*1024, HBSTART +  8*128*1024 - 1},
95    {HBSTART +  8*128*1024, HBSTART +  9*128*1024 - 1},
96    {HBSTART +  9*128*1024, HBSTART + 10*128*1024 - 1},
97    {HBSTART + 10*128*1024, HBSTART + 11*128*1024 - 1},
98    {HBSTART + 11*128*1024, HBSTART + 12*128*1024 - 1},
99    {HBSTART + 12*128*1024, HBSTART + 13*128*1024 - 1},
100    {HBSTART + 13*128*1024, HBSTART + 14*128*1024 - 1},
101    {HBSTART + 14*128*1024, HBSTART + 15*128*1024 - 1},
102    {HBSTART + 15*128*1024, HBSTART + 16*128*1024 - 1},
103    {HBSTART + 16*128*1024, HBSTART + 17*128*1024 - 1},
104    {HBSTART + 17*128*1024, HBSTART + 18*128*1024 - 1},
105    {HBSTART + 18*128*1024, HBSTART + 19*128*1024 - 1},
106    {HBSTART + 19*128*1024, HBSTART + 20*128*1024 - 1},
107};
108
109/* Set bits in a bitmask to indicate which banks are
110 * within the range "first" and "last".
111 */
112static void
113range_set(
114  uint32_t first,
115  uint32_t last,
116  int *p_bits,
117  const struct range *pr,
118  int n_range
119)
120{
121    int i;
122    int bits = 0;
123    for (i = 0; i < n_range; i++) {
124        /* If the upper limit is less than "first" or the lower limit
125         * is greater than "last" then the block is not in range.
126         */
127        if ( !(pr[i].upper < first || pr[i].lower > last)) {
128            bits |= (1 << i);   /* This block is in the range, set the bit. */
129        }
130
131    }
132    *p_bits = bits;
133}
134
135#define N(ARG) (sizeof(ARG)/sizeof(ARG[0]))
136
137/** Return the size of the on-chip flash
138 *  verifying that this is a device that we know about.
139 * @return 0 for OK, non-zero for error:
140 *  - MPC55XX_FLASH_VERIFY_ERR for LAS not 6 or MAS not 0.
141 *    @note This is overriding what verify means!
142 *  - MPC55XX_FLASH_SIZE_ERR Not a chip I've checked against the manual,
143 *                           athat is, SIZE not 5, 7, or 11.
144 */
145int
146mpc55xx_flash_size(
147  uint32_t *p_size  /**< The size is returned here. */
148)
149{
150    /* On the MPC5553, MPC5554, MPC5566, and MP5567 the
151     *  low address space LAS field is 0x6 and all have
152     *  six blocks sized 2*16k, 2*48k, and 2*64k.
153     *
154     * All the mid and high address spaces have 128K blocks.
155     *
156     * The mid address space MAS size field is 0 for the above machines,
157     * and they all have 2 128K blocks.
158     *
159     * For the high address space we look at the
160     * size field to figure out the size.  The SIZE field is:
161     *
162     * 5 for 1.5MB (MPC5553)
163     * 7 for 2MB (MPC5554, MPC5567)
164     * 11 for 3MB  (MPC5566)
165     */
166    int hblocks;    /* The number of blocks in the high address space. */
167
168    /* Verify the configuration matches one of the chips that I've checked out.
169     */
170    if (FLASH.MCR.B.LAS != 6 || FLASH.MCR.B.MAS != 0) {
171        return MPC55XX_FLASH_VERIFY_ERR;
172    }
173
174    switch(FLASH.MCR.B.SIZE) {
175        case 5:
176        hblocks = 8;
177        break;
178
179        case 7:
180        hblocks = 12;
181        break;
182
183        case 11:
184        hblocks = 20;
185        break;
186
187        default:
188        return MPC55XX_FLASH_SIZE_ERR;
189    }
190
191    /* The first two banks are 256K.
192     * The high block has "hblocks" 128K blocks.
193     */
194    *p_size = 256*1024 + 256*1024 + hblocks * 128*1024;
195    return 0;
196}
197
198/* Unlock the flash blocks if "p_locked" points to something that is 0.
199 * If it is a NULL pointer then we aren't allowed to do the unlock.
200 */
201static int
202unlock_once(int lsel, int msel, int hbsel, int *p_locked)
203{
204    union LMLR_tag lmlr;
205    union SLMLR_tag slmlr;
206    union HLR_tag hlr;
207    rtems_interrupt_level level;
208
209    /* If we're already locked return.
210     */
211    if (p_locked && (*p_locked == 1)) {
212        return 0;
213    }
214
215    /* Do we have to lock something in the low or mid block?
216     */
217    rtems_interrupt_disable(level);
218    lmlr = FLASH.LMLR;
219    if ((lsel || msel) && (lmlr.B.LME == 0)) {
220        union LMLR_tag lmlr_unlock;
221        lmlr_unlock.B.LLOCK=~lsel;
222        lmlr_unlock.B.MLOCK=~msel;
223        lmlr_unlock.B.SLOCK=1;
224
225        if (lmlr.B.LLOCK != lmlr_unlock.B.LLOCK ||
226        lmlr.B.MLOCK != lmlr_unlock.B.MLOCK) {
227            if (p_locked == 0) {
228                rtems_interrupt_enable(level);
229                return MPC55XX_FLASH_LOCK_ERR;
230            } else {
231                *p_locked = 1;
232            }
233            FLASH.LMLR.R = 0xA1A11111;  /* Unlock. */
234            FLASH.LMLR = lmlr_unlock;
235        }
236    }
237    rtems_interrupt_enable(level);
238
239    rtems_interrupt_disable(level);
240    slmlr = FLASH.SLMLR;
241    if ((lsel || msel) && (slmlr.B.SLE == 0)) {
242        union SLMLR_tag slmlr_unlock;
243        slmlr_unlock.B.SLLOCK=~lsel;
244        slmlr_unlock.B.SMLOCK=~msel;
245        slmlr_unlock.B.SSLOCK=1;
246
247        if (slmlr.B.SLLOCK != slmlr_unlock.B.SLLOCK ||
248        slmlr.B.SMLOCK != slmlr_unlock.B.SMLOCK) {
249            if (p_locked == 0) {
250                rtems_interrupt_enable(level);
251                return MPC55XX_FLASH_LOCK_ERR;
252            } else {
253                *p_locked = 1;
254            }
255            FLASH.SLMLR.R = 0xC3C33333;  /* Unlock. */
256            FLASH.SLMLR = slmlr_unlock;
257        }
258    }
259    rtems_interrupt_enable(level);
260
261    /* Do we have to unlock something in the high block?
262     */
263    rtems_interrupt_disable(level);
264    hlr = FLASH.HLR;
265    if (hbsel && (hlr.B.HBE == 0)) {
266        union HLR_tag hlr_unlock;
267        hlr_unlock.B.HBLOCK = ~hbsel;
268
269        if (hlr.B.HBLOCK != hlr_unlock.B.HBLOCK) {
270            if (p_locked == 0) {
271                return MPC55XX_FLASH_LOCK_ERR;
272                rtems_interrupt_enable(level);
273            } else {
274                *p_locked = 1;
275            }
276            FLASH.HLR.R = 0xB2B22222;   /* Unlock. */
277            FLASH.HLR = hlr_unlock;
278        }
279    }
280    rtems_interrupt_enable(level);
281
282    return 0;
283}
284
285static inline uint32_t
286tsize(int i)
287{
288  return 1 << (10 + 2 * i);
289}
290
291static int
292addr_map(
293  int to_phys,         /* If 1 lookup physical else lookup mapped. */
294  const void *addr,    /* The address to look up. */
295  uint32_t *p_result   /* Result is here. */
296)
297{
298    uint32_t u_addr = (uint32_t)addr;
299    uint32_t mas0, mas1, mas2, mas3;
300    uint32_t start, end;
301    rtems_interrupt_level level;
302    int i;
303
304    for (i = 0; i < 32; i++) {
305      mas0 = 0x10000000 | (i << 16);
306      rtems_interrupt_disable(level);
307      PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS0, mas0);
308      asm volatile("tlbre");
309      mas1 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS1);
310      mas2 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS2);
311      mas3 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3);
312      rtems_interrupt_enable(level);
313
314      if (mas1 & 0x80000000) {
315        /* Valid. */
316        start = (to_phys ? mas2 : mas3) & 0xFFFFF000;
317        end = start + tsize((mas1 >> 8) & 0x0000000F);
318        /* Are we within range?
319         */
320        if (start <= u_addr && end >= u_addr) {
321          uint32_t offset = (to_phys ? mas3 : mas2) & 0xFFFFF000;
322          *p_result = u_addr - offset;
323          return 0;
324        }
325      }
326    }
327
328    /* Not found in a TLB.
329     */
330    return ESRCH;
331}
332
333/** Return the physical address corresponding to a mapped address.
334  @return 0 if OK, ESRCH if not found in TLB1.
335 **/
336int
337mpc55xx_physical_address(
338  const void *addr,     /**< Mapped address. */
339  uint32_t *p_result    /**< Result returned here. */
340)
341{
342    return addr_map(1, addr, p_result);
343}
344
345/** Return the mapped address corresponding to a mapped address.
346  @return 0 if OK, ESRCH if not found in TLB1.
347 **/
348int
349mpc55xx_mapped_address(
350  const void *addr,     /**< Mapped address. */
351  uint32_t *p_result    /**< Result returned here. */
352)
353{
354    return addr_map(0, addr, p_result);
355}
356
357/**
358 * Copy memory from an address into the flash when flash is relocated
359 * If programming fails the address that it failed at can be returned.
360 @note At end of operation the flash may be left writable.
361 *     Use mpc55xx_flash_read_only() to set read-only.
362 @return Zero for OK, non-zero for error:
363 * - ESRCH                       Can't lookup where something lives.
364 * - EPERM                       Attempt to write to non-writable flash.
365 * - ETXTBSY                     Attempt to flash overlapping regions.
366 * - MPC55XX_FLASH_CONFIG_ERR    for LAS not 6 or MAS not 0.
367 * - MPC55XX_FLASH_SIZE_ERR      for SIZE not 5, 7, or 11.
368 * - MPC55XX_FLASH_RANGE_ERR     for illegal access:
369 *                               - first or first+last outside of flash;
370 *                               - first not on a mod(8) boundary;
371 *                               - nbytes not multiple of 8.
372 * - MPC55XX_FLASH_ERASE_ERR     Erase requested but failed.
373 * - MPC55XX_FLASH_PROGRAM_ERR   Program requested but failed.
374 * - MPC55XX_FLASH_NOT_BLANK_ERR Blank check requested but not blank.
375 * - MPC55XX_FLASH_VERIFY_ERR    Verify requested but failed.
376 * - MPC55XX_FLASH_LOCK_ERR      Unlock requested but failed.
377 **/
378
379int
380mpc55xx_flash_copy_op(
381  void *dest,       /**< An address in the flash to copy to. */
382  const void *src,  /**< An address in memory to copy from. */
383  size_t nbytes,    /**< The number of bytes to copy. */
384  uint32_t opmask,  /**< Bitmask of operations to perform.
385                     * - MPC55XX_FLASH_UNLOCK:      Unlock the blocks.
386                     * - MPC55XX_FLASH_ERASE:       Erase the blocks.
387                     * - MPC55XX_FLASH_BLANK_CHECK: Verify the blocks are blank.
388                     * - MPC55XX_FLASH_PROGRAM:     Program the FLASH.
389                     * - MPC55XX_FLASH_VERIFY:      Verify the regions match.
390                     **/
391  uint32_t *p_fail  /**< If not NULL then the address where the operation
392                     *   failed is returned here.
393                     **/
394)
395{
396    uint32_t udest, usrc, flash_size;
397    int r;
398    int peg;            /* Program or Erase Good - Did it work? */
399
400    int lsel;           /* Low block select bits. */
401    int msel;           /* Mid block select bits. */
402    int hbsel;          /* High block select bits. */
403
404    int s_lsel;           /* Source Low block select bits. */
405    int s_msel;           /* Source Mid block select bits. */
406    int s_hbsel;          /* Source High block select bits. */
407
408    int unlocked = 0;
409    int *p_unlocked;
410    int i;
411    int nwords;         /* The number of 32 bit words to write. */
412    volatile uint32_t *flash;    /* Where the flash is mapped in. */
413    volatile uint32_t *memory;   /* What to copy into flash. */
414    uint32_t offset;    /* Where the FLASH is mapped into memory. */
415    rtems_interrupt_level level;
416
417    if ( (r = mpc55xx_flash_size(&flash_size))) {
418        return r;
419    }
420
421    /* Get where the flash is mapped in.
422     */
423    offset = mpc55xx_flash_address();
424
425    udest = ((uint32_t)dest) - offset;
426    if ( (r = mpc55xx_physical_address(src, &usrc)) ) {
427      return r;
428    }
429
430    /* Verify that the address being programmed is in flash and that it is
431     * a multiple of 64 bits.
432     * Someone else can remove the 64-bit restriction.
433     */
434    if (udest > flash_size ||
435    udest + nbytes > flash_size ||
436    (udest & 0x7) != 0 ||
437    (nbytes & 0x7) != 0) {
438        return MPC55XX_FLASH_RANGE_ERR;
439    }
440
441    if (opmask == 0) {
442        return 0;
443    }
444
445    /* If we're going to do a write-style operation the flash must be writable.
446     */
447    if ((opmask &
448        (MPC55XX_FLASH_UNLOCK | MPC55XX_FLASH_ERASE | MPC55XX_FLASH_PROGRAM)) &&
449        !mpc55xx_flash_writable()
450    ) {
451      return EPERM;
452    }
453
454    /* If we aren't allowed to unlock then set the pointer to zero.
455     * That is how "unlock_once" decides we can't unlock.
456     */
457    p_unlocked = (opmask & MPC55XX_FLASH_UNLOCK) ? &unlocked : 0;
458
459    /* Set up the bit masks for the blocks to program or erase.
460     */
461    range_set(udest, udest + nbytes, &lsel,   lsel_ranges, N( lsel_ranges));
462    range_set(udest, udest + nbytes, &msel,   msel_ranges, N( msel_ranges));
463    range_set(udest, udest + nbytes, &hbsel, hbsel_ranges, N(hbsel_ranges));
464
465    range_set(usrc, usrc + nbytes, &s_lsel,   lsel_ranges, N( lsel_ranges));
466    range_set(usrc, usrc + nbytes, &s_msel,   msel_ranges, N( msel_ranges));
467    range_set(usrc, usrc + nbytes, &s_hbsel, hbsel_ranges, N(hbsel_ranges));
468
469    /* Are we attempting overlapping flash?
470     */
471    if ((lsel & s_lsel) | (msel & s_msel) | (hbsel & s_hbsel)) {
472      return ETXTBSY;
473    }
474
475    nwords = nbytes / 4;
476    flash = (volatile uint32_t *)dest;
477    memory = (volatile uint32_t *)src;
478
479  /* In the following sections any "Step N" notes refer to
480   * the steps in "13.4.2.3 Flash Programming" in the reference manual.
481   * XXX Do parts of this neeed to be protected by interrupt locks?
482   */
483
484    if (opmask & MPC55XX_FLASH_ERASE) {   /* Erase. */
485        if ( (r = unlock_once(lsel, msel, hbsel, p_unlocked)) ) {
486            return r;
487        }
488
489        rtems_interrupt_disable(level);
490        FLASH.MCR.B.ERS = 1;        /* Step 1: Select erase. */
491
492        FLASH.LMSR.B.LSEL = lsel;   /* Step 2: Select blocks to be erased. */
493        FLASH.LMSR.B.MSEL = msel;
494        FLASH.HSR.B.HBSEL = hbsel;
495
496        flash[0] = 1;               /* Step 3: Write to any address in the flash
497                                     * (the "erase interlock write)".
498                                     */
499        FLASH.MCR.B.EHV = 1;         /* Step 4: Enable high V to start erase. */
500        rtems_interrupt_enable(level);
501        while (FLASH.MCR.B.DONE == 0) { /* Step 5: Wait until done. */
502        }
503        rtems_interrupt_disable(level);
504        peg = FLASH.MCR.B.PEG;       /* Save result. */
505        FLASH.MCR.B.EHV = 0;         /* Disable high voltage. */
506        FLASH.MCR.B.ERS = 0;         /* De-select erase. */
507        rtems_interrupt_enable(level);
508        if (peg == 0) {
509            return MPC55XX_FLASH_ERASE_ERR; /* Flash erase failed. */
510        }
511    }
512
513    if (opmask & MPC55XX_FLASH_BLANK_CHECK) {    /* Verify blank. */
514        for (i = 0; i < nwords; i++) {
515           if (flash[i] != 0xffffffff) {
516                if (p_fail) {
517                    *p_fail = (uint32_t)(flash + i);
518                }
519                return MPC55XX_FLASH_NOT_BLANK_ERR; /* Not blank. */
520           }
521        }
522    }
523
524  /* Program.
525   */
526    if (opmask & MPC55XX_FLASH_PROGRAM) {
527        int chunk = 0;  /* Used to collect programming into 256 bit chunks. */
528
529        if ( (r = unlock_once(lsel, msel, hbsel, p_unlocked)) ) {
530            return r;
531        }
532        FLASH.MCR.B.PGM = 1;                /* Step 1 */
533
534       rtems_interrupt_disable(level);
535
536        for (i = 0; i < nwords; i += 2) {
537           flash[i] = memory[i];            /* Step 2 */
538           flash[i + 1] = memory[i + 1];    /* Always program in min 64 bits. */
539
540          /* Step 3 is "write additional words" */
541
542           /* Try to program in chunks of 256 bits.
543            * Collect the 64 bit writes into 256 bit ones:
544            */
545           chunk++;
546           if (chunk == 4) {
547                /* Collected 4 64-bits for a 256 bit chunk. */
548                FLASH.MCR.B.EHV = 1;            /* Step 4: Enable high V. */
549
550                rtems_interrupt_enable(level);
551                while (FLASH.MCR.B.DONE == 0) { /* Step 5: Wait until done. */
552                }
553                rtems_interrupt_disable(level);
554
555                peg = FLASH.MCR.B.PEG;          /* Step 6: Save result. */
556                FLASH.MCR.B.EHV = 0;            /* Step 7: Disable high V. */
557                if (peg == 0) {
558                    FLASH.MCR.B.PGM = 0;
559                    rtems_interrupt_enable(level);
560                    if (p_fail) {
561                        *p_fail = (uint32_t)(flash + i);
562                    }
563                    return MPC55XX_FLASH_PROGRAM_ERR; /* Programming failed. */
564                }
565                chunk = 0;                       /* Reset chunk counter. */
566            }
567                                                 /* Step 8: Back to step 2. */
568        }
569
570       if (!chunk) {
571            FLASH.MCR.B.PGM = 0;
572            rtems_interrupt_enable(level);
573       } else {
574           /* If there is anything left in that last chunk flush it out:
575            */
576            FLASH.MCR.B.EHV = 1;
577
578            rtems_interrupt_enable(level);
579            while (FLASH.MCR.B.DONE == 0) {     /* Wait until done. */
580            }
581            rtems_interrupt_disable(level);
582
583            peg = FLASH.MCR.B.PEG;              /* Save result. */
584            FLASH.MCR.B.EHV = 0;                /* Disable high voltage. */
585            FLASH.MCR.B.PGM = 0;
586            rtems_interrupt_enable(level);
587
588            if (peg == 0) {
589                if (p_fail) {
590                    *p_fail = (uint32_t)(flash + i);
591                }
592                return MPC55XX_FLASH_PROGRAM_ERR; /* Programming failed. */
593            }
594        }
595    }
596
597    if (opmask & MPC55XX_FLASH_VERIFY) {        /* Verify memory matches. */
598        for (i = 0; i < nwords; i++) {
599           if (flash[i] != memory[i]) {
600                if (p_fail) {              /* Return the failed address. */
601                    *p_fail = (uint32_t)(flash + i);
602                }
603                return MPC55XX_FLASH_VERIFY_ERR; /* Verification failed. */
604           }
605        }
606    }
607
608    return 0;
609}
610
611/** Simple flash copy with a signature that matches memcpy.
612 @note At end of operation the flash may be left writable.
613 *     Use mpc55xx_flash_read_only() to set read-only.
614 @return Zero for OK, non-zero for error.
615 *       see flash_copy_op() for possible errors.
616 **/
617int
618mpc55xx_flash_copy(
619  void *dest,       /**< An address in the flash to copy to. */
620  const void *src,  /**< An address in the flash copy from. */
621  size_t nbytes     /**< The number of bytes to copy. */
622)
623{
624    return mpc55xx_flash_copy_op(dest, src, nbytes,
625        (MPC55XX_FLASH_UNLOCK      |
626         MPC55XX_FLASH_ERASE       |
627         MPC55XX_FLASH_BLANK_CHECK |
628         MPC55XX_FLASH_PROGRAM     |
629         MPC55XX_FLASH_VERIFY      ), 0);
630}
631
632/** Make the flash read-write.
633 @note This assumes the flash is mapped by TLB1 entry 1.
634 */
635void
636mpc55xx_flash_set_read_write(void)
637{
638    rtems_interrupt_level level;
639    rtems_interrupt_disable(level);
640    PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
641    asm volatile("tlbre");
642    PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(FSL_EIS_MAS3, 0x0000000C);
643    asm volatile("tlbwe");
644    rtems_interrupt_enable(level);
645}
646
647/** Make the flash read-only.
648 @note This assumes the flash is mapped by TLB1 entry 1.
649 */
650void
651mpc55xx_flash_set_read_only(void)
652{
653    rtems_interrupt_level level;
654    rtems_interrupt_disable(level);
655    PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
656    asm volatile("tlbre");
657    PPC_CLEAR_SPECIAL_PURPOSE_REGISTER_BITS(FSL_EIS_MAS3, 0x0000000C);
658    asm volatile("tlbwe");
659    rtems_interrupt_enable(level);
660}
661
662/** See if the flash is writable.
663 *  @note This assumes the flash is mapped by TLB1 entry 1.
664 *  @note It needs to be writable by both user and supervisor.
665 */
666int
667mpc55xx_flash_writable(void)
668{
669    uint32_t mas3;
670    rtems_interrupt_level level;
671
672    rtems_interrupt_disable(level);
673    PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
674    asm volatile("tlbre");
675    mas3 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3);
676    rtems_interrupt_enable(level);
677
678    return ((mas3 & 0x0000000C) == 0x0000000C) ? 1 : 0;
679}
680
681/** Return the address where the flash is mapped in.
682 @note This assumes the flash is mapped by TLB1 entry 1.
683 **/
684uint32_t
685mpc55xx_flash_address(void)
686{
687    uint32_t mas2;
688    rtems_interrupt_level level;
689
690    rtems_interrupt_disable(level);
691    PPC_SET_SPECIAL_PURPOSE_REGISTER( FSL_EIS_MAS0, 0x10010000);
692    asm volatile("tlbre");
693    mas2 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS2);
694    rtems_interrupt_enable(level);
695
696    return mas2 & 0xFFFFF000;
697}
Note: See TracBrowser for help on using the repository browser.