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