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