1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2006,2010 Freescale Semiconductor 4 * Jeff Brown 5 * Srikanth Srinivasan (srikanth.srinivasan@freescale.com) 6 */ 7 8 #include <common.h> 9 #include <command.h> 10 #include <asm/io.h> 11 12 #define pixis_base (u8 *)PIXIS_BASE 13 14 /* 15 * Simple board reset. 16 */ 17 void pixis_reset(void) 18 { 19 out_8(pixis_base + PIXIS_RST, 0); 20 21 while (1); 22 } 23 24 /* 25 * Per table 27, page 58 of MPC8641HPCN spec. 26 */ 27 static int set_px_sysclk(unsigned long sysclk) 28 { 29 u8 sysclk_s, sysclk_r, sysclk_v, vclkh, vclkl, sysclk_aux; 30 31 switch (sysclk) { 32 case 33: 33 sysclk_s = 0x04; 34 sysclk_r = 0x04; 35 sysclk_v = 0x07; 36 sysclk_aux = 0x00; 37 break; 38 case 40: 39 sysclk_s = 0x01; 40 sysclk_r = 0x1F; 41 sysclk_v = 0x20; 42 sysclk_aux = 0x01; 43 break; 44 case 50: 45 sysclk_s = 0x01; 46 sysclk_r = 0x1F; 47 sysclk_v = 0x2A; 48 sysclk_aux = 0x02; 49 break; 50 case 66: 51 sysclk_s = 0x01; 52 sysclk_r = 0x04; 53 sysclk_v = 0x04; 54 sysclk_aux = 0x03; 55 break; 56 case 83: 57 sysclk_s = 0x01; 58 sysclk_r = 0x1F; 59 sysclk_v = 0x4B; 60 sysclk_aux = 0x04; 61 break; 62 case 100: 63 sysclk_s = 0x01; 64 sysclk_r = 0x1F; 65 sysclk_v = 0x5C; 66 sysclk_aux = 0x05; 67 break; 68 case 134: 69 sysclk_s = 0x06; 70 sysclk_r = 0x1F; 71 sysclk_v = 0x3B; 72 sysclk_aux = 0x06; 73 break; 74 case 166: 75 sysclk_s = 0x06; 76 sysclk_r = 0x1F; 77 sysclk_v = 0x4B; 78 sysclk_aux = 0x07; 79 break; 80 default: 81 printf("Unsupported SYSCLK frequency.\n"); 82 return 0; 83 } 84 85 vclkh = (sysclk_s << 5) | sysclk_r; 86 vclkl = sysclk_v; 87 88 out_8(pixis_base + PIXIS_VCLKH, vclkh); 89 out_8(pixis_base + PIXIS_VCLKL, vclkl); 90 91 out_8(pixis_base + PIXIS_AUX, sysclk_aux); 92 93 return 1; 94 } 95 96 /* Set the CFG_SYSPLL bits 97 * 98 * This only has effect if PX_VCFGEN0[SYSPLL]=1, which is true if 99 * read_from_px_regs() is called. 100 */ 101 static int set_px_mpxpll(unsigned long mpxpll) 102 { 103 switch (mpxpll) { 104 case 2: 105 case 4: 106 case 6: 107 case 8: 108 case 10: 109 case 12: 110 case 14: 111 case 16: 112 clrsetbits_8(pixis_base + PIXIS_VSPEED1, 0x1F, mpxpll); 113 return 1; 114 } 115 116 printf("Unsupported MPXPLL ratio.\n"); 117 return 0; 118 } 119 120 static int set_px_corepll(unsigned long corepll) 121 { 122 u8 val; 123 124 switch (corepll) { 125 case 20: 126 val = 0x08; 127 break; 128 case 25: 129 val = 0x0C; 130 break; 131 case 30: 132 val = 0x10; 133 break; 134 case 35: 135 val = 0x1C; 136 break; 137 case 40: 138 val = 0x14; 139 break; 140 case 45: 141 val = 0x0E; 142 break; 143 default: 144 printf("Unsupported COREPLL ratio.\n"); 145 return 0; 146 } 147 148 clrsetbits_8(pixis_base + PIXIS_VSPEED0, 0x1F, val); 149 return 1; 150 } 151 152 #ifndef CONFIG_SYS_PIXIS_VCFGEN0_ENABLE 153 #define CONFIG_SYS_PIXIS_VCFGEN0_ENABLE 0x1C 154 #endif 155 156 /* Tell the PIXIS where to find the COREPLL, MPXPLL, SYSCLK values 157 * 158 * The PIXIS can be programmed to look at either the on-board dip switches 159 * or various other PIXIS registers to determine the values for COREPLL, 160 * MPXPLL, and SYSCLK. 161 * 162 * CONFIG_SYS_PIXIS_VCFGEN0_ENABLE is the value to write to the PIXIS_VCFGEN0 163 * register that tells the pixis to use the various PIXIS register. 164 */ 165 static void read_from_px_regs(int set) 166 { 167 u8 tmp = in_8(pixis_base + PIXIS_VCFGEN0); 168 169 if (set) 170 tmp = tmp | CONFIG_SYS_PIXIS_VCFGEN0_ENABLE; 171 else 172 tmp = tmp & ~CONFIG_SYS_PIXIS_VCFGEN0_ENABLE; 173 174 out_8(pixis_base + PIXIS_VCFGEN0, tmp); 175 } 176 177 /* CONFIG_SYS_PIXIS_VBOOT_ENABLE is the value to write to the PX_VCFGEN1 178 * register that tells the pixis to use the PX_VBOOT[LBMAP] register. 179 */ 180 #ifndef CONFIG_SYS_PIXIS_VBOOT_ENABLE 181 #define CONFIG_SYS_PIXIS_VBOOT_ENABLE 0x04 182 #endif 183 184 /* Configure the source of the boot location 185 * 186 * The PIXIS can be programmed to look at either the on-board dip switches 187 * or the PX_VBOOT[LBMAP] register to determine where we should boot. 188 * 189 * If we want to boot from the alternate boot bank, we need to tell the PIXIS 190 * to ignore the on-board dip switches and use the PX_VBOOT[LBMAP] instead. 191 */ 192 static void read_from_px_regs_altbank(int set) 193 { 194 u8 tmp = in_8(pixis_base + PIXIS_VCFGEN1); 195 196 if (set) 197 tmp = tmp | CONFIG_SYS_PIXIS_VBOOT_ENABLE; 198 else 199 tmp = tmp & ~CONFIG_SYS_PIXIS_VBOOT_ENABLE; 200 201 out_8(pixis_base + PIXIS_VCFGEN1, tmp); 202 } 203 204 /* CONFIG_SYS_PIXIS_VBOOT_MASK contains the bits to set in VBOOT register that 205 * tells the PIXIS what the alternate flash bank is. 206 * 207 * Note that it's not really a mask. It contains the actual LBMAP bits that 208 * must be set to select the alternate bank. This code assumes that the 209 * primary bank has these bits set to 0, and the alternate bank has these 210 * bits set to 1. 211 */ 212 #ifndef CONFIG_SYS_PIXIS_VBOOT_MASK 213 #define CONFIG_SYS_PIXIS_VBOOT_MASK (0x40) 214 #endif 215 216 /* Tell the PIXIS to boot from the default flash bank 217 * 218 * Program the default flash bank into the VBOOT register. This register is 219 * used only if PX_VCFGEN1[FLASH]=1. 220 */ 221 static void clear_altbank(void) 222 { 223 clrbits_8(pixis_base + PIXIS_VBOOT, CONFIG_SYS_PIXIS_VBOOT_MASK); 224 } 225 226 /* Tell the PIXIS to boot from the alternate flash bank 227 * 228 * Program the alternate flash bank into the VBOOT register. This register is 229 * used only if PX_VCFGEN1[FLASH]=1. 230 */ 231 static void set_altbank(void) 232 { 233 setbits_8(pixis_base + PIXIS_VBOOT, CONFIG_SYS_PIXIS_VBOOT_MASK); 234 } 235 236 /* Reset the board with watchdog disabled. 237 * 238 * This respects the altbank setting. 239 */ 240 static void set_px_go(void) 241 { 242 /* Disable the VELA sequencer and watchdog */ 243 clrbits_8(pixis_base + PIXIS_VCTL, 9); 244 245 /* Reboot by starting the VELA sequencer */ 246 setbits_8(pixis_base + PIXIS_VCTL, 0x1); 247 248 while (1); 249 } 250 251 /* Reset the board with watchdog enabled. 252 * 253 * This respects the altbank setting. 254 */ 255 static void set_px_go_with_watchdog(void) 256 { 257 /* Disable the VELA sequencer */ 258 clrbits_8(pixis_base + PIXIS_VCTL, 1); 259 260 /* Enable the watchdog and reboot by starting the VELA sequencer */ 261 setbits_8(pixis_base + PIXIS_VCTL, 0x9); 262 263 while (1); 264 } 265 266 /* Disable the watchdog 267 * 268 */ 269 static int pixis_disable_watchdog_cmd(cmd_tbl_t *cmdtp, int flag, int argc, 270 char * const argv[]) 271 { 272 /* Disable the VELA sequencer and the watchdog */ 273 clrbits_8(pixis_base + PIXIS_VCTL, 9); 274 275 return 0; 276 } 277 278 U_BOOT_CMD( 279 diswd, 1, 0, pixis_disable_watchdog_cmd, 280 "Disable watchdog timer", 281 "" 282 ); 283 284 #ifdef CONFIG_PIXIS_SGMII_CMD 285 286 /* Enable or disable SGMII mode for a TSEC 287 */ 288 static int pixis_set_sgmii(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 289 { 290 int which_tsec = -1; 291 unsigned char mask; 292 unsigned char switch_mask; 293 294 if ((argc > 2) && (strcmp(argv[1], "all") != 0)) 295 which_tsec = simple_strtoul(argv[1], NULL, 0); 296 297 switch (which_tsec) { 298 #ifdef CONFIG_TSEC1 299 case 1: 300 mask = PIXIS_VSPEED2_TSEC1SER; 301 switch_mask = PIXIS_VCFGEN1_TSEC1SER; 302 break; 303 #endif 304 #ifdef CONFIG_TSEC2 305 case 2: 306 mask = PIXIS_VSPEED2_TSEC2SER; 307 switch_mask = PIXIS_VCFGEN1_TSEC2SER; 308 break; 309 #endif 310 #ifdef CONFIG_TSEC3 311 case 3: 312 mask = PIXIS_VSPEED2_TSEC3SER; 313 switch_mask = PIXIS_VCFGEN1_TSEC3SER; 314 break; 315 #endif 316 #ifdef CONFIG_TSEC4 317 case 4: 318 mask = PIXIS_VSPEED2_TSEC4SER; 319 switch_mask = PIXIS_VCFGEN1_TSEC4SER; 320 break; 321 #endif 322 default: 323 mask = PIXIS_VSPEED2_MASK; 324 switch_mask = PIXIS_VCFGEN1_MASK; 325 break; 326 } 327 328 /* Toggle whether the switches or FPGA control the settings */ 329 if (!strcmp(argv[argc - 1], "switch")) 330 clrbits_8(pixis_base + PIXIS_VCFGEN1, switch_mask); 331 else 332 setbits_8(pixis_base + PIXIS_VCFGEN1, switch_mask); 333 334 /* If it's not the switches, enable or disable SGMII, as specified */ 335 if (!strcmp(argv[argc - 1], "on")) 336 clrbits_8(pixis_base + PIXIS_VSPEED2, mask); 337 else if (!strcmp(argv[argc - 1], "off")) 338 setbits_8(pixis_base + PIXIS_VSPEED2, mask); 339 340 return 0; 341 } 342 343 U_BOOT_CMD( 344 pixis_set_sgmii, CONFIG_SYS_MAXARGS, 1, pixis_set_sgmii, 345 "pixis_set_sgmii" 346 " - Enable or disable SGMII mode for a given TSEC \n", 347 "\npixis_set_sgmii [TSEC num] <on|off|switch>\n" 348 " TSEC num: 1,2,3,4 or 'all'. 'all' is default.\n" 349 " on - enables SGMII\n" 350 " off - disables SGMII\n" 351 " switch - use switch settings" 352 ); 353 354 #endif 355 356 /* 357 * This function takes the non-integral cpu:mpx pll ratio 358 * and converts it to an integer that can be used to assign 359 * FPGA register values. 360 * input: strptr i.e. argv[2] 361 */ 362 static unsigned long strfractoint(char *strptr) 363 { 364 int i, j; 365 int mulconst; 366 int no_dec = 0; 367 unsigned long intval = 0, decval = 0; 368 char intarr[3], decarr[3]; 369 370 /* Assign the integer part to intarr[] 371 * If there is no decimal point i.e. 372 * if the ratio is an integral value 373 * simply create the intarr. 374 */ 375 i = 0; 376 while (strptr[i] != '.') { 377 if (strptr[i] == 0) { 378 no_dec = 1; 379 break; 380 } 381 intarr[i] = strptr[i]; 382 i++; 383 } 384 385 intarr[i] = '\0'; 386 387 if (no_dec) { 388 /* Currently needed only for single digit corepll ratios */ 389 mulconst = 10; 390 decval = 0; 391 } else { 392 j = 0; 393 i++; /* Skipping the decimal point */ 394 while ((strptr[i] >= '0') && (strptr[i] <= '9')) { 395 decarr[j] = strptr[i]; 396 i++; 397 j++; 398 } 399 400 decarr[j] = '\0'; 401 402 mulconst = 1; 403 for (i = 0; i < j; i++) 404 mulconst *= 10; 405 decval = simple_strtoul(decarr, NULL, 10); 406 } 407 408 intval = simple_strtoul(intarr, NULL, 10); 409 intval = intval * mulconst; 410 411 return intval + decval; 412 } 413 414 static int pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 415 { 416 unsigned int i; 417 char *p_cf = NULL; 418 char *p_cf_sysclk = NULL; 419 char *p_cf_corepll = NULL; 420 char *p_cf_mpxpll = NULL; 421 char *p_altbank = NULL; 422 char *p_wd = NULL; 423 int unknown_param = 0; 424 425 /* 426 * No args is a simple reset request. 427 */ 428 if (argc <= 1) { 429 pixis_reset(); 430 /* not reached */ 431 } 432 433 for (i = 1; i < argc; i++) { 434 if (strcmp(argv[i], "cf") == 0) { 435 p_cf = argv[i]; 436 if (i + 3 >= argc) { 437 break; 438 } 439 p_cf_sysclk = argv[i+1]; 440 p_cf_corepll = argv[i+2]; 441 p_cf_mpxpll = argv[i+3]; 442 i += 3; 443 continue; 444 } 445 446 if (strcmp(argv[i], "altbank") == 0) { 447 p_altbank = argv[i]; 448 continue; 449 } 450 451 if (strcmp(argv[i], "wd") == 0) { 452 p_wd = argv[i]; 453 continue; 454 } 455 456 unknown_param = 1; 457 } 458 459 /* 460 * Check that cf has all required parms 461 */ 462 if ((p_cf && !(p_cf_sysclk && p_cf_corepll && p_cf_mpxpll)) 463 || unknown_param) { 464 #ifdef CONFIG_SYS_LONGHELP 465 puts(cmdtp->help); 466 putc('\n'); 467 #endif 468 return 1; 469 } 470 471 /* 472 * PIXIS seems to be sensitive to the ordering of 473 * the registers that are touched. 474 */ 475 read_from_px_regs(0); 476 477 if (p_altbank) 478 read_from_px_regs_altbank(0); 479 480 clear_altbank(); 481 482 /* 483 * Clock configuration specified. 484 */ 485 if (p_cf) { 486 unsigned long sysclk; 487 unsigned long corepll; 488 unsigned long mpxpll; 489 490 sysclk = simple_strtoul(p_cf_sysclk, NULL, 10); 491 corepll = strfractoint(p_cf_corepll); 492 mpxpll = simple_strtoul(p_cf_mpxpll, NULL, 10); 493 494 if (!(set_px_sysclk(sysclk) 495 && set_px_corepll(corepll) 496 && set_px_mpxpll(mpxpll))) { 497 #ifdef CONFIG_SYS_LONGHELP 498 puts(cmdtp->help); 499 putc('\n'); 500 #endif 501 return 1; 502 } 503 read_from_px_regs(1); 504 } 505 506 /* 507 * Altbank specified 508 * 509 * NOTE CHANGE IN BEHAVIOR: previous code would default 510 * to enabling watchdog if altbank is specified. 511 * Now the watchdog must be enabled explicitly using 'wd'. 512 */ 513 if (p_altbank) { 514 set_altbank(); 515 read_from_px_regs_altbank(1); 516 } 517 518 /* 519 * Reset with watchdog specified. 520 */ 521 if (p_wd) 522 set_px_go_with_watchdog(); 523 else 524 set_px_go(); 525 526 /* 527 * Shouldn't be reached. 528 */ 529 return 0; 530 } 531 532 533 U_BOOT_CMD( 534 pixis_reset, CONFIG_SYS_MAXARGS, 1, pixis_reset_cmd, 535 "Reset the board using the FPGA sequencer", 536 " pixis_reset\n" 537 " pixis_reset [altbank]\n" 538 " pixis_reset altbank wd\n" 539 " pixis_reset altbank cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n" 540 " pixis_reset cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>" 541 ); 542