File indexing completed on 2025-05-11 08:23:56
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
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
0044
0045
0046
0047
0048
0049
0050
0051
0052 struct range {
0053 uint32_t lower;
0054 uint32_t upper;
0055 };
0056
0057
0058
0059
0060
0061
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
0073
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
0082
0083
0084
0085
0086
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
0113
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
0128
0129
0130 if ( !(pr[i].upper < first || pr[i].lower > last)) {
0131 bits |= (1 << i);
0132 }
0133
0134 }
0135 *p_bits = bits;
0136 }
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 int
0147 mpc55xx_flash_size(
0148 uint32_t *p_size
0149 )
0150 {
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167 int hblocks;
0168
0169
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
0193
0194
0195 *p_size = 256*1024 + 256*1024 + hblocks * 128*1024;
0196 return 0;
0197 }
0198
0199
0200
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
0210
0211 if (p_locked && (*p_locked == 1)) {
0212 return 0;
0213 }
0214
0215
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;
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;
0251 FLASH.SLMLR = slmlr_unlock;
0252 }
0253 }
0254
0255
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;
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,
0285 const void *addr,
0286 uint32_t *p_result
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
0307 start = (to_phys ? mas2 : mas3) & 0xFFFFF000;
0308 end = start + tsize((mas1 >> 8) & 0x0000000F);
0309
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
0320
0321 return ESRCH;
0322 }
0323
0324
0325
0326
0327 int
0328 mpc55xx_physical_address(
0329 const void *addr,
0330 uint32_t *p_result
0331 )
0332 {
0333 return addr_map(1, addr, p_result);
0334 }
0335
0336
0337
0338
0339 int
0340 mpc55xx_mapped_address(
0341 const void *addr,
0342 uint32_t *p_result
0343 )
0344 {
0345 return addr_map(0, addr, p_result);
0346 }
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370 int
0371 mpc55xx_flash_copy_op(
0372 void *dest,
0373 const void *src,
0374 size_t nbytes,
0375 uint32_t opmask,
0376
0377
0378
0379
0380
0381
0382 uint32_t *p_fail
0383
0384
0385 )
0386 {
0387 uint32_t udest, usrc, flash_size;
0388 int r;
0389 int peg;
0390
0391 int lsel;
0392 int msel;
0393 int hbsel;
0394
0395 int s_lsel;
0396 int s_msel;
0397 int s_hbsel;
0398
0399 int unlocked = 0;
0400 int *p_unlocked;
0401 int i;
0402 int nwords;
0403 volatile uint32_t *flash;
0404 volatile uint32_t *memory;
0405 const void *flashing_from;
0406
0407 uint32_t offset;
0408
0409 if ( (r = mpc55xx_flash_size(&flash_size))) {
0410 return r;
0411 }
0412
0413
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
0423
0424
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
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
0447
0448
0449 p_unlocked = (opmask & MPC55XX_FLASH_UNLOCK) ? &unlocked : 0;
0450
0451
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
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
0472
0473
0474
0475 if (opmask & MPC55XX_FLASH_ERASE) {
0476 uint32_t flash_biucr_r;
0477 if ( (r = unlock_once(lsel, msel, hbsel, p_unlocked)) ) {
0478 return r;
0479 }
0480
0481
0482 flash_biucr_r = FLASH.BIUCR.R;
0483 FLASH.BIUCR.B.PFLIM = 0;
0484
0485 FLASH.MCR.B.ESUS = 0;
0486
0487 FLASH.MCR.B.ERS = 1;
0488
0489 FLASH.LMSR.B.LSEL = lsel;
0490 FLASH.LMSR.B.MSEL = msel;
0491 FLASH.HSR.B.HBSEL = hbsel;
0492
0493 flash[0] = 0xffffffff;
0494
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;
0502 while (FLASH.MCR.B.DONE == 0) {
0503 }
0504 peg = FLASH.MCR.B.PEG;
0505 FLASH.MCR.B.EHV = 0;
0506 FLASH.MCR.B.ERS = 0;
0507 FLASH.BIUCR.R = flash_biucr_r;
0508
0509 if (peg == 0) {
0510 return MPC55XX_FLASH_ERASE_ERR;
0511 }
0512 }
0513
0514 if (opmask & MPC55XX_FLASH_BLANK_CHECK) {
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;
0521 }
0522 }
0523 }
0524
0525
0526
0527 if (opmask & MPC55XX_FLASH_PROGRAM) {
0528 int chunk = 0;
0529
0530 if ( (r = unlock_once(lsel, msel, hbsel, p_unlocked)) ) {
0531 return r;
0532 }
0533 FLASH.MCR.B.PGM = 1;
0534
0535 for (flashing_from = (const void *)flash, i = 0; i < nwords; i += 2) {
0536 flash[i] = memory[i];
0537 flash[i + 1] = memory[i + 1];
0538
0539
0540
0541
0542
0543
0544 chunk++;
0545 if (chunk == 4) {
0546
0547
0548 rtems_cache_flush_multiple_data_lines(flashing_from, 32);
0549
0550 FLASH.MCR.B.EHV = 1;
0551
0552 while (FLASH.MCR.B.DONE == 0) {
0553 }
0554
0555 peg = FLASH.MCR.B.PEG;
0556 FLASH.MCR.B.EHV = 0;
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;
0563 }
0564 chunk = 0;
0565 flashing_from = (const void *)(flash + i);
0566 }
0567
0568 }
0569
0570 if (!chunk) {
0571 FLASH.MCR.B.PGM = 0;
0572 } else {
0573
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) {
0581 }
0582
0583 peg = FLASH.MCR.B.PEG;
0584 FLASH.MCR.B.EHV = 0;
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;
0592 }
0593 }
0594 }
0595
0596 if (opmask & MPC55XX_FLASH_VERIFY) {
0597 for (i = 0; i < nwords; i++) {
0598 if (flash[i] != memory[i]) {
0599 if (p_fail) {
0600 *p_fail = (uint32_t)(flash + i);
0601 }
0602 return MPC55XX_FLASH_VERIFY_ERR;
0603 }
0604 }
0605 }
0606
0607 return 0;
0608 }
0609
0610
0611
0612
0613
0614
0615
0616 int
0617 mpc55xx_flash_copy(
0618 void *dest,
0619 const void *src,
0620 size_t nbytes
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
0632
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
0647
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
0662
0663
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
0681
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