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 29 #ifdef CONFIG_FSL_PIXIS 30 #include <asm/cache.h> 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; 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; 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 CFG_PIXIS_VBOOT_MASK 211 #define CFG_PIXIS_VBOOT_MASK 0x40 212 #endif 213 214 void set_altbank(void) 215 { 216 u8 tmp; 217 218 tmp = in8(PIXIS_BASE + PIXIS_VBOOT); 219 tmp ^= CFG_PIXIS_VBOOT_MASK; 220 221 out8(PIXIS_BASE + PIXIS_VBOOT, tmp); 222 } 223 224 225 void set_px_go(void) 226 { 227 u8 tmp; 228 229 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 230 tmp = tmp & 0x1E; 231 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 232 233 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 234 tmp = tmp | 0x01; 235 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 236 } 237 238 239 void set_px_go_with_watchdog(void) 240 { 241 u8 tmp; 242 243 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 244 tmp = tmp & 0x1E; 245 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 246 247 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 248 tmp = tmp | 0x09; 249 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 250 } 251 252 253 int pixis_disable_watchdog_cmd(cmd_tbl_t *cmdtp, 254 int flag, int argc, char *argv[]) 255 { 256 u8 tmp; 257 258 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 259 tmp = tmp & 0x1E; 260 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 261 262 /* setting VCTL[WDEN] to 0 to disable watch dog */ 263 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 264 tmp &= ~0x08; 265 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 266 267 return 0; 268 } 269 270 U_BOOT_CMD( 271 diswd, 1, 0, pixis_disable_watchdog_cmd, 272 "diswd - Disable watchdog timer \n", 273 NULL); 274 275 /* 276 * This function takes the non-integral cpu:mpx pll ratio 277 * and converts it to an integer that can be used to assign 278 * FPGA register values. 279 * input: strptr i.e. argv[2] 280 */ 281 282 static ulong strfractoint(uchar *strptr) 283 { 284 int i, j, retval; 285 int mulconst; 286 int intarr_len = 0, decarr_len = 0, no_dec = 0; 287 ulong intval = 0, decval = 0; 288 uchar intarr[3], decarr[3]; 289 290 /* Assign the integer part to intarr[] 291 * If there is no decimal point i.e. 292 * if the ratio is an integral value 293 * simply create the intarr. 294 */ 295 i = 0; 296 while (strptr[i] != 46) { 297 if (strptr[i] == 0) { 298 no_dec = 1; 299 break; 300 } 301 intarr[i] = strptr[i]; 302 i++; 303 } 304 305 /* Assign length of integer part to intarr_len. */ 306 intarr_len = i; 307 intarr[i] = '\0'; 308 309 if (no_dec) { 310 /* Currently needed only for single digit corepll ratios */ 311 mulconst = 10; 312 decval = 0; 313 } else { 314 j = 0; 315 i++; /* Skipping the decimal point */ 316 while ((strptr[i] > 47) && (strptr[i] < 58)) { 317 decarr[j] = strptr[i]; 318 i++; 319 j++; 320 } 321 322 decarr_len = j; 323 decarr[j] = '\0'; 324 325 mulconst = 1; 326 for (i = 0; i < decarr_len; i++) 327 mulconst *= 10; 328 decval = simple_strtoul((char *)decarr, NULL, 10); 329 } 330 331 intval = simple_strtoul((char *)intarr, NULL, 10); 332 intval = intval * mulconst; 333 334 retval = intval + decval; 335 336 return retval; 337 } 338 339 340 int 341 pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 342 { 343 ulong val; 344 ulong corepll; 345 346 /* 347 * No args is a simple reset request. 348 */ 349 if (argc <= 1) { 350 pixis_reset(); 351 /* not reached */ 352 } 353 354 if (strcmp(argv[1], "cf") == 0) { 355 356 /* 357 * Reset with frequency changed: 358 * cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio> 359 */ 360 if (argc < 5) { 361 puts(cmdtp->usage); 362 return 1; 363 } 364 365 read_from_px_regs(0); 366 367 val = set_px_sysclk(simple_strtoul(argv[2], NULL, 10)); 368 369 corepll = strfractoint((uchar *)argv[3]); 370 val = val + set_px_corepll(corepll); 371 val = val + set_px_mpxpll(simple_strtoul(argv[4], NULL, 10)); 372 if (val == 3) { 373 puts("Setting registers VCFGEN0 and VCTL\n"); 374 read_from_px_regs(1); 375 puts("Resetting board with values from "); 376 puts("VSPEED0, VSPEED1, VCLKH, and VCLKL \n"); 377 set_px_go(); 378 } else { 379 puts(cmdtp->usage); 380 return 1; 381 } 382 383 while (1) ; /* Not reached */ 384 385 } else if (strcmp(argv[1], "altbank") == 0) { 386 387 /* 388 * Reset using alternate flash bank: 389 */ 390 if (argv[2] == 0) { 391 /* 392 * Reset from alternate bank without changing 393 * frequency and without watchdog timer enabled. 394 * altbank 395 */ 396 read_from_px_regs(0); 397 read_from_px_regs_altbank(0); 398 if (argc > 2) { 399 puts(cmdtp->usage); 400 return 1; 401 } 402 puts("Setting registers VCFGNE1, VBOOT, and VCTL\n"); 403 set_altbank(); 404 read_from_px_regs_altbank(1); 405 puts("Resetting board to boot from the other bank.\n"); 406 set_px_go(); 407 408 } else if (strcmp(argv[2], "cf") == 0) { 409 /* 410 * Reset with frequency changed 411 * altbank cf <SYSCLK freq> <COREPLL ratio> 412 * <MPXPLL ratio> 413 */ 414 read_from_px_regs(0); 415 read_from_px_regs_altbank(0); 416 val = set_px_sysclk(simple_strtoul(argv[3], NULL, 10)); 417 corepll = strfractoint((uchar *)argv[4]); 418 val = val + set_px_corepll(corepll); 419 val = val + set_px_mpxpll(simple_strtoul(argv[5], 420 NULL, 10)); 421 if (val == 3) { 422 puts("Setting registers VCFGEN0, VCFGEN1, VBOOT, and VCTL\n"); 423 set_altbank(); 424 read_from_px_regs(1); 425 read_from_px_regs_altbank(1); 426 puts("Enabling watchdog timer on the FPGA\n"); 427 puts("Resetting board with values from "); 428 puts("VSPEED0, VSPEED1, VCLKH and VCLKL "); 429 puts("to boot from the other bank.\n"); 430 set_px_go_with_watchdog(); 431 } else { 432 puts(cmdtp->usage); 433 return 1; 434 } 435 436 while (1) ; /* Not reached */ 437 438 } else if (strcmp(argv[2], "wd") == 0) { 439 /* 440 * Reset from alternate bank without changing 441 * frequencies but with watchdog timer enabled: 442 * altbank wd 443 */ 444 read_from_px_regs(0); 445 read_from_px_regs_altbank(0); 446 puts("Setting registers VCFGEN1, VBOOT, and VCTL\n"); 447 set_altbank(); 448 read_from_px_regs_altbank(1); 449 puts("Enabling watchdog timer on the FPGA\n"); 450 puts("Resetting board to boot from the other bank.\n"); 451 set_px_go_with_watchdog(); 452 while (1) ; /* Not reached */ 453 454 } else { 455 puts(cmdtp->usage); 456 return 1; 457 } 458 459 } else { 460 puts(cmdtp->usage); 461 return 1; 462 } 463 464 return 0; 465 } 466 467 468 U_BOOT_CMD( 469 pixis_reset, CFG_MAXARGS, 1, pixis_reset_cmd, 470 "pixis_reset - Reset the board using the FPGA sequencer\n", 471 " pixis_reset\n" 472 " pixis_reset [altbank]\n" 473 " pixis_reset altbank wd\n" 474 " pixis_reset altbank cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n" 475 " pixis_reset cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n" 476 ); 477 #endif /* CONFIG_FSL_PIXIS */ 478