File indexing completed on 2025-05-11 08:23:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <rtems.h>
0021 #include <libcpu/bat.h>
0022 #include <libcpu/spr.h>
0023 #include <rtems/bspIo.h>
0024
0025 #include <libcpu/cpuIdent.h>
0026
0027 #define TYP_I 1
0028 #define TYP_D 0
0029
0030 typedef union
0031 {
0032 BAT bat;
0033 struct
0034 {
0035 unsigned int u, l;
0036 } words;
0037 } ubat;
0038
0039 typedef struct batrange
0040 {
0041 unsigned long start;
0042 unsigned long limit;
0043 unsigned long phys;
0044 } batrange;
0045
0046 batrange bat_addrs[2][8] = { { {0,} } };
0047
0048
0049
0050 static unsigned bat_in_use[2] = { 0, 0 };
0051
0052
0053
0054 #define CLRBAT_ASM(batu,r) \
0055 " sync \n" \
0056 " isync \n" \
0057 " li "#r ", 0 \n" \
0058 " mtspr "#batu ", "#r "\n" \
0059 " sync \n" \
0060 " isync \n"
0061
0062 #define SETBAT_ASM(batu, batl, u, l)\
0063 " mtspr "#batl ", "#l " \n" \
0064 " sync \n" \
0065 " isync \n" \
0066 " mtspr "#batu ", "#u " \n" \
0067 " sync \n" \
0068 " isync \n"
0069
0070 #define CLRBAT(bat) \
0071 asm volatile( \
0072 CLRBAT_ASM(%0, 0) \
0073 : \
0074 :"i"(bat##U) \
0075 :"0")
0076
0077 #define GETBAT(bat,u,l) \
0078 asm volatile( \
0079 " mfspr %0, %2 \n" \
0080 " mfspr %1, %3 \n" \
0081 :"=r"(u),"=r"(l) \
0082 :"i"(bat##U),"i"(bat##L) \
0083 )
0084
0085 #define DECL_SETBAT(lcbat,bat) \
0086 void \
0087 asm_set##lcbat(unsigned int upper, unsigned int lower) \
0088 { \
0089 asm volatile( \
0090 CLRBAT_ASM(%0,0) \
0091 SETBAT_ASM(%0,%1,%2,%3) \
0092 : \
0093 :"i"(bat##U), \
0094 "i"(bat##L), \
0095 "r"(upper),"r"(lower) \
0096 :"0"); \
0097 }
0098
0099
0100 DECL_SETBAT (dbat0, DBAT0)
0101 DECL_SETBAT (dbat1, DBAT1)
0102 DECL_SETBAT (dbat2, DBAT2)
0103 DECL_SETBAT (dbat3, DBAT3)
0104
0105 static DECL_SETBAT (dbat4, DBAT4)
0106 static DECL_SETBAT (dbat5, DBAT5)
0107 static DECL_SETBAT (dbat6, DBAT6)
0108 static DECL_SETBAT (dbat7, DBAT7)
0109
0110 static DECL_SETBAT (ibat0, IBAT0)
0111 static DECL_SETBAT (ibat1, IBAT1)
0112 static DECL_SETBAT (ibat2, IBAT2)
0113 static DECL_SETBAT (ibat3, IBAT3)
0114 static DECL_SETBAT (ibat4, IBAT4)
0115 static DECL_SETBAT (ibat5, IBAT5)
0116 static DECL_SETBAT (ibat6, IBAT6)
0117 static DECL_SETBAT (ibat7, IBAT7)
0118
0119
0120 SPR_RO (HID0);
0121
0122 static void
0123 set_hid0_sync (unsigned long val)
0124 {
0125 __asm__ volatile (
0126 " sync \n"
0127 " isync \n"
0128 " mtspr %0, %1 \n"
0129 " sync \n"
0130 " isync \n"
0131 :
0132 :"i" (HID0), "r" (val)
0133 :"memory"
0134 );
0135 }
0136
0137 static void
0138 bat_addrs_put (ubat * bat, int typ, int idx)
0139 {
0140 unsigned long bl;
0141 if (bat->bat.batu.vp || bat->bat.batu.vs) {
0142 bat_addrs[typ][idx].start = bat->bat.batu.bepi << 17;
0143 bat_addrs[typ][idx].phys = bat->bat.batl.brpn << 17;
0144
0145
0146
0147
0148
0149 bl = (bat->words.u << 15) | ((1 << 17) - 1);
0150 bat_addrs[typ][idx].limit = bat_addrs[typ][idx].start + bl;
0151
0152 bat_in_use[typ] |= (1 << idx);
0153 }
0154 }
0155
0156
0157
0158
0159
0160 static void
0161 bat_addrs_init (void)
0162 {
0163 ubat bat;
0164
0165 GETBAT (DBAT0, bat.words.u, bat.words.l);
0166 bat_addrs_put (&bat, TYP_D, 0);
0167 GETBAT (DBAT1, bat.words.u, bat.words.l);
0168 bat_addrs_put (&bat, TYP_D, 1);
0169 GETBAT (DBAT2, bat.words.u, bat.words.l);
0170 bat_addrs_put (&bat, TYP_D, 2);
0171 GETBAT (DBAT3, bat.words.u, bat.words.l);
0172 bat_addrs_put (&bat, TYP_D, 3);
0173
0174 GETBAT (IBAT0, bat.words.u, bat.words.l);
0175 bat_addrs_put (&bat, TYP_I, 0);
0176 GETBAT (IBAT1, bat.words.u, bat.words.l);
0177 bat_addrs_put (&bat, TYP_I, 1);
0178 GETBAT (IBAT2, bat.words.u, bat.words.l);
0179 bat_addrs_put (&bat, TYP_I, 2);
0180 GETBAT (IBAT3, bat.words.u, bat.words.l);
0181 bat_addrs_put (&bat, TYP_I, 3);
0182
0183
0184 if ( ppc_cpu_has_8_bats() && (HID0_7455_HIGH_BAT_EN & _read_HID0 ())) {
0185 GETBAT (DBAT4, bat.words.u, bat.words.l);
0186 bat_addrs_put (&bat, TYP_D, 4);
0187 GETBAT (DBAT5, bat.words.u, bat.words.l);
0188 bat_addrs_put (&bat, TYP_D, 5);
0189 GETBAT (DBAT6, bat.words.u, bat.words.l);
0190 bat_addrs_put (&bat, TYP_D, 6);
0191 GETBAT (DBAT7, bat.words.u, bat.words.l);
0192 bat_addrs_put (&bat, TYP_D, 7);
0193 GETBAT (IBAT4, bat.words.u, bat.words.l);
0194 bat_addrs_put (&bat, TYP_I, 4);
0195 GETBAT (IBAT5, bat.words.u, bat.words.l);
0196 bat_addrs_put (&bat, TYP_I, 5);
0197 GETBAT (IBAT6, bat.words.u, bat.words.l);
0198 bat_addrs_put (&bat, TYP_I, 6);
0199 GETBAT (IBAT7, bat.words.u, bat.words.l);
0200 bat_addrs_put (&bat, TYP_I, 7);
0201 }
0202 }
0203
0204 static void
0205 do_dssall (void)
0206 {
0207
0208
0209
0210
0211
0212
0213
0214 if ( (_read_MSR () & MSR_VE) && PPC_PSIM != get_ppc_cpu_type() ) {
0215
0216
0217
0218
0219
0220
0221 #define DSSALL 0x7e00066c
0222 __asm__ volatile (" .long %0"::"i" (DSSALL));
0223 #undef DSSALL
0224 }
0225 }
0226
0227
0228 static void
0229 clear_hi_bats (void)
0230 {
0231 do_dssall ();
0232 CLRBAT (DBAT4);
0233 CLRBAT (DBAT5);
0234 CLRBAT (DBAT6);
0235 CLRBAT (DBAT7);
0236 CLRBAT (IBAT4);
0237 CLRBAT (IBAT5);
0238 CLRBAT (IBAT6);
0239 CLRBAT (IBAT7);
0240 }
0241
0242 static int
0243 check_bat_index (int i)
0244 {
0245 unsigned long hid0;
0246
0247 if (i >= 0 && i < 4)
0248 return 0;
0249 if (i >= 4 && i < 8) {
0250 if ( ! ppc_cpu_has_8_bats() )
0251 return -1;
0252
0253
0254
0255 hid0 = _read_HID0 ();
0256 if (HID0_7455_HIGH_BAT_EN & hid0)
0257 return 0;
0258
0259 clear_hi_bats ();
0260 set_hid0_sync (hid0 | HID0_7455_HIGH_BAT_EN);
0261 return 0;
0262 }
0263 return -1;
0264 }
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275 static int
0276 check_bat_size (unsigned long size)
0277 {
0278 unsigned long bit;
0279 unsigned long hid0;
0280
0281
0282 if (0 == size)
0283 return 0;
0284
0285 if (0xffffffff == size) {
0286 bit = 32;
0287 } else {
0288 __asm__ volatile (" cntlzw %0, %1":"=r" (bit):"r" (size));
0289 bit = 31 - bit;
0290 if (1 << bit != size)
0291 return -1;
0292 }
0293
0294 if (bit > (11 + 17)) {
0295 if ( ! ppc_cpu_has_8_bats() )
0296 return -1;
0297
0298 hid0 = _read_HID0 ();
0299
0300 if (!(HID0_7455_XBSEN & hid0))
0301 set_hid0_sync (hid0 | HID0_7455_XBSEN);
0302 }
0303
0304 return (1 << (bit - 17)) - 1;
0305 }
0306
0307 static int
0308 check_overlap (int typ, unsigned long start, unsigned long size)
0309 {
0310 int i;
0311 unsigned long limit = start + size - 1;
0312 for (i = 0; i < sizeof (bat_addrs[typ]) / sizeof (bat_addrs[typ][0]); i++) {
0313 if (!((1 << i) & bat_in_use[typ]))
0314 continue;
0315
0316 if (limit >= bat_addrs[typ][i].start && start <= bat_addrs[typ][i].limit)
0317 return i;
0318 }
0319 return -1;
0320 }
0321
0322
0323
0324
0325
0326
0327 static int
0328 setbat (int typ, int bat_index, unsigned long virt, unsigned long phys,
0329 unsigned int size, int flags)
0330 {
0331 unsigned long level;
0332 unsigned int bl;
0333 int err;
0334 int wimgxpp;
0335 ubat bat;
0336
0337 if (check_bat_index (bat_index)) {
0338 printk ("Invalid BAT index %d\n", bat_index);
0339 return -1;
0340 }
0341
0342 if ((int) (bl = check_bat_size (size)) < 0) {
0343 printk ("Invalid BAT size %u\n", size);
0344 return -1;
0345 }
0346
0347 if (virt & (size - 1)) {
0348 printk ("BAT effective address 0x%08lx misaligned (size is 0x%08x)\n",
0349 virt, size);
0350 return -1;
0351 }
0352
0353 if (phys & (size - 1)) {
0354 printk ("BAT physical address 0x%08lx misaligned (size is 0x%08x)\n", phys,
0355 size);
0356 return -1;
0357 }
0358
0359 if (virt + size - 1 < virt) {
0360 printk ("BAT range invalid: wraps around zero 0x%08lx..0x%08lx\n", virt,
0361 virt + size - 1);
0362 return -1;
0363 }
0364
0365 if ( TYP_I == typ && ( ( _PAGE_GUARDED | _PAGE_WRITETHRU ) & flags ) ) {
0366 printk("IBAT must not have 'guarded' or 'writethrough' attribute\n");
0367 return -1;
0368 }
0369
0370
0371
0372
0373 rtems_interrupt_disable (level);
0374
0375 {
0376 static char init_done = 0;
0377 if (!init_done) {
0378 bat_addrs_init ();
0379 init_done = 1;
0380 }
0381 }
0382
0383 err = check_overlap (typ, virt, size);
0384 if ((size >= (1 << 17)) && (err >= 0) && (err != bat_index)) {
0385 rtems_interrupt_enable (level);
0386 printk ("BATs must not overlap; area 0x%08lx..0x%08lx hits %cBAT %i\n",
0387 virt, virt + size, (TYP_I == typ ? 'I' : 'D'), err);
0388 return -1;
0389 }
0390
0391
0392 wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
0393 | _PAGE_COHERENT | _PAGE_GUARDED);
0394 wimgxpp |= (flags & _PAGE_RW) ? BPP_RW : BPP_RX;
0395 bat.words.u = virt | (bl << 2) | 2;
0396 bat.words.l = phys | wimgxpp;
0397 if (flags & _PAGE_USER)
0398 bat.bat.batu.vp = 1;
0399 bat_addrs[typ][bat_index].start = virt;
0400 bat_addrs[typ][bat_index].limit = virt + ((bl + 1) << 17) - 1;
0401 bat_addrs[typ][bat_index].phys = phys;
0402 bat_in_use[typ] |= 1 << bat_index;
0403 if (size < (1 << 17)) {
0404
0405 bat.bat.batu.vp = 0;
0406 bat.bat.batu.vs = 0;
0407 bat_in_use[typ] &= ~(1 << bat_index);
0408
0409
0410
0411 bat_addrs[typ][bat_index].limit = virt;
0412 }
0413 do_dssall ();
0414 if ( TYP_I == typ ) {
0415 switch (bat_index) {
0416 case 0: asm_setibat0 (bat.words.u, bat.words.l); break;
0417 case 1: asm_setibat1 (bat.words.u, bat.words.l); break;
0418 case 2: asm_setibat2 (bat.words.u, bat.words.l); break;
0419 case 3: asm_setibat3 (bat.words.u, bat.words.l); break;
0420
0421 case 4: asm_setibat4 (bat.words.u, bat.words.l); break;
0422 case 5: asm_setibat5 (bat.words.u, bat.words.l); break;
0423 case 6: asm_setibat6 (bat.words.u, bat.words.l); break;
0424 case 7: asm_setibat7 (bat.words.u, bat.words.l); break;
0425 default:
0426 break;
0427 }
0428 } else {
0429 switch (bat_index) {
0430 case 0: asm_setdbat0 (bat.words.u, bat.words.l); break;
0431 case 1: asm_setdbat1 (bat.words.u, bat.words.l); break;
0432 case 2: asm_setdbat2 (bat.words.u, bat.words.l); break;
0433 case 3: asm_setdbat3 (bat.words.u, bat.words.l); break;
0434
0435 case 4: asm_setdbat4 (bat.words.u, bat.words.l); break;
0436 case 5: asm_setdbat5 (bat.words.u, bat.words.l); break;
0437 case 6: asm_setdbat6 (bat.words.u, bat.words.l); break;
0438 case 7: asm_setdbat7 (bat.words.u, bat.words.l); break;
0439 default:
0440 break;
0441 }
0442 }
0443 rtems_interrupt_enable (level);
0444
0445 return 0;
0446 }
0447
0448 static int
0449 getbat (int typ, int idx, unsigned long *pu, unsigned long *pl)
0450 {
0451 unsigned long u, l;
0452
0453 if (check_bat_index (idx)) {
0454 printk ("Invalid BAT #%i\n", idx);
0455 return -1;
0456 }
0457 if ( TYP_I == typ ) {
0458 switch (idx) {
0459 case 0: GETBAT (IBAT0, u, l); break;
0460 case 1: GETBAT (IBAT1, u, l); break;
0461 case 2: GETBAT (IBAT2, u, l); break;
0462 case 3: GETBAT (IBAT3, u, l); break;
0463
0464 case 4: GETBAT (IBAT4, u, l); break;
0465 case 5: GETBAT (IBAT5, u, l); break;
0466 case 6: GETBAT (IBAT6, u, l); break;
0467 case 7: GETBAT (IBAT7, u, l); break;
0468 default:
0469 return -1;
0470 }
0471 } else {
0472 switch (idx) {
0473 case 0: GETBAT (DBAT0, u, l); break;
0474 case 1: GETBAT (DBAT1, u, l); break;
0475 case 2: GETBAT (DBAT2, u, l); break;
0476 case 3: GETBAT (DBAT3, u, l); break;
0477
0478 case 4: GETBAT (DBAT4, u, l); break;
0479 case 5: GETBAT (DBAT5, u, l); break;
0480 case 6: GETBAT (DBAT6, u, l); break;
0481 case 7: GETBAT (DBAT7, u, l); break;
0482 default:
0483 return -1;
0484 }
0485 }
0486 if (pu) {
0487 *pu = u;
0488 }
0489 if (pl) {
0490 *pl = l;
0491 }
0492
0493 if (!pu && !pl) {
0494
0495 ubat b;
0496 b.words.u = u;
0497 b.words.l = l;
0498 printk ("Raw %cBAT %i contents; UPPER: (0x%08lx)", (TYP_I == typ ? 'I' : 'D'), idx, u);
0499 printk (" BEPI: 0x%08x", b.bat.batu.bepi);
0500 printk (" BL: 0x%08lx", (u >> 2) & ((1 << 15) - 1));
0501 printk (" VS: 0b%i", b.bat.batu.vs);
0502 printk (" VP: 0b%i", b.bat.batu.vp);
0503 printk ("\n");
0504 printk (" LOWER: (0x%08lx)", l);
0505 printk (" RPN: 0x%08x", b.bat.batl.brpn);
0506 printk (" wimg: 0b%1i%1i%1i%1i", b.bat.batl.w, b.bat.batl.i,
0507 b.bat.batl.m, b.bat.batl.g);
0508 printk (" PP: 0x%1x", b.bat.batl.pp);
0509 printk ("\n");
0510 printk ("Covering EA Range: ");
0511 if (bat_in_use[typ] & (1 << idx))
0512 printk ("0x%08lx .. 0x%08lx\n", bat_addrs[typ][idx].start,
0513 bat_addrs[typ][idx].limit);
0514 else
0515 printk ("<none> (BAT off)\n");
0516
0517 }
0518 return u;
0519 }
0520
0521 int
0522 setdbat (int bat_index, unsigned long virt, unsigned long phys,
0523 unsigned int size, int flags)
0524 {
0525 return setbat(TYP_D, bat_index, virt, phys, size, flags);
0526 }
0527
0528 int
0529 setibat (int bat_index, unsigned long virt, unsigned long phys,
0530 unsigned int size, int flags)
0531 {
0532 return setbat(TYP_I, bat_index, virt, phys, size, flags);
0533 }
0534
0535 int
0536 getdbat (int idx, unsigned long *pu, unsigned long *pl)
0537 {
0538 return getbat (TYP_D, idx, pu, pl);
0539 }
0540
0541 int
0542 getibat (int idx, unsigned long *pu, unsigned long *pl)
0543 {
0544 return getbat (TYP_I, idx, pu, pl);
0545 }