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

4.11
Last change on this file since e2d3e37 was e2d3e37, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 10, 2011 at 8:22:27 AM

2011-10-10 Sebastian Huber <sebastian.huber@…>

PR 1928/bsps:

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