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