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