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

4.115
Last change on this file since dc661c8 was dc661c8, checked in by Peter Dufault <dufault@…>, on Aug 20, 2014 at 10:08:23 PM

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