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 30 #ifdef CONFIG_FSL_PIXIS 31 32 #include "pixis.h" 33 34 35 static ulong strfractoint(uchar *strptr); 36 37 38 /* 39 * Simple board reset. 40 */ 41 void pixis_reset(void) 42 { 43 out8(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 54 switch (sysclk) { 55 case 33: 56 sysclk_s = 0x04; 57 sysclk_r = 0x04; 58 sysclk_v = 0x07; 59 sysclk_aux = 0x00; 60 break; 61 case 40: 62 sysclk_s = 0x01; 63 sysclk_r = 0x1F; 64 sysclk_v = 0x20; 65 sysclk_aux = 0x01; 66 break; 67 case 50: 68 sysclk_s = 0x01; 69 sysclk_r = 0x1F; 70 sysclk_v = 0x2A; 71 sysclk_aux = 0x02; 72 break; 73 case 66: 74 sysclk_s = 0x01; 75 sysclk_r = 0x04; 76 sysclk_v = 0x04; 77 sysclk_aux = 0x03; 78 break; 79 case 83: 80 sysclk_s = 0x01; 81 sysclk_r = 0x1F; 82 sysclk_v = 0x4B; 83 sysclk_aux = 0x04; 84 break; 85 case 100: 86 sysclk_s = 0x01; 87 sysclk_r = 0x1F; 88 sysclk_v = 0x5C; 89 sysclk_aux = 0x05; 90 break; 91 case 134: 92 sysclk_s = 0x06; 93 sysclk_r = 0x1F; 94 sysclk_v = 0x3B; 95 sysclk_aux = 0x06; 96 break; 97 case 166: 98 sysclk_s = 0x06; 99 sysclk_r = 0x1F; 100 sysclk_v = 0x4B; 101 sysclk_aux = 0x07; 102 break; 103 default: 104 printf("Unsupported SYSCLK frequency.\n"); 105 return 0; 106 } 107 108 vclkh = (sysclk_s << 5) | sysclk_r; 109 vclkl = sysclk_v; 110 111 out8(PIXIS_BASE + PIXIS_VCLKH, vclkh); 112 out8(PIXIS_BASE + PIXIS_VCLKL, vclkl); 113 114 out8(PIXIS_BASE + PIXIS_AUX, sysclk_aux); 115 116 return 1; 117 } 118 119 120 int set_px_mpxpll(ulong mpxpll) 121 { 122 u8 tmp; 123 u8 val; 124 125 switch (mpxpll) { 126 case 2: 127 case 4: 128 case 6: 129 case 8: 130 case 10: 131 case 12: 132 case 14: 133 case 16: 134 val = (u8) mpxpll; 135 break; 136 default: 137 printf("Unsupported MPXPLL ratio.\n"); 138 return 0; 139 } 140 141 tmp = in8(PIXIS_BASE + PIXIS_VSPEED1); 142 tmp = (tmp & 0xF0) | (val & 0x0F); 143 out8(PIXIS_BASE + PIXIS_VSPEED1, tmp); 144 145 return 1; 146 } 147 148 149 int set_px_corepll(ulong corepll) 150 { 151 u8 tmp; 152 u8 val; 153 154 switch ((int)corepll) { 155 case 20: 156 val = 0x08; 157 break; 158 case 25: 159 val = 0x0C; 160 break; 161 case 30: 162 val = 0x10; 163 break; 164 case 35: 165 val = 0x1C; 166 break; 167 case 40: 168 val = 0x14; 169 break; 170 case 45: 171 val = 0x0E; 172 break; 173 default: 174 printf("Unsupported COREPLL ratio.\n"); 175 return 0; 176 } 177 178 tmp = in8(PIXIS_BASE + PIXIS_VSPEED0); 179 tmp = (tmp & 0xE0) | (val & 0x1F); 180 out8(PIXIS_BASE + PIXIS_VSPEED0, tmp); 181 182 return 1; 183 } 184 185 186 void read_from_px_regs(int set) 187 { 188 u8 mask = 0x1C; 189 u8 tmp = in8(PIXIS_BASE + PIXIS_VCFGEN0); 190 191 if (set) 192 tmp = tmp | mask; 193 else 194 tmp = tmp & ~mask; 195 out8(PIXIS_BASE + PIXIS_VCFGEN0, tmp); 196 } 197 198 199 void read_from_px_regs_altbank(int set) 200 { 201 u8 mask = 0x04; 202 u8 tmp = in8(PIXIS_BASE + PIXIS_VCFGEN1); 203 204 if (set) 205 tmp = tmp | mask; 206 else 207 tmp = tmp & ~mask; 208 out8(PIXIS_BASE + PIXIS_VCFGEN1, tmp); 209 } 210 211 212 void set_altbank(void) 213 { 214 u8 tmp; 215 216 tmp = in8(PIXIS_BASE + PIXIS_VBOOT); 217 tmp ^= 0x40; 218 219 out8(PIXIS_BASE + PIXIS_VBOOT, tmp); 220 } 221 222 223 void set_px_go(void) 224 { 225 u8 tmp; 226 227 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 228 tmp = tmp & 0x1E; 229 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 230 231 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 232 tmp = tmp | 0x01; 233 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 234 } 235 236 237 void set_px_go_with_watchdog(void) 238 { 239 u8 tmp; 240 241 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 242 tmp = tmp & 0x1E; 243 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 244 245 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 246 tmp = tmp | 0x09; 247 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 248 } 249 250 251 int pixis_disable_watchdog_cmd(cmd_tbl_t *cmdtp, 252 int flag, int argc, char *argv[]) 253 { 254 u8 tmp; 255 256 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 257 tmp = tmp & 0x1E; 258 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 259 260 /* setting VCTL[WDEN] to 0 to disable watch dog */ 261 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 262 tmp &= ~0x08; 263 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 264 265 return 0; 266 } 267 268 U_BOOT_CMD( 269 diswd, 1, 0, pixis_disable_watchdog_cmd, 270 "diswd - Disable watchdog timer \n", 271 NULL); 272 273 /* 274 * This function takes the non-integral cpu:mpx pll ratio 275 * and converts it to an integer that can be used to assign 276 * FPGA register values. 277 * input: strptr i.e. argv[2] 278 */ 279 280 static ulong strfractoint(uchar *strptr) 281 { 282 int i, j, retval; 283 int mulconst; 284 int intarr_len = 0, decarr_len = 0, no_dec = 0; 285 ulong intval = 0, decval = 0; 286 uchar intarr[3], decarr[3]; 287 288 /* Assign the integer part to intarr[] 289 * If there is no decimal point i.e. 290 * if the ratio is an integral value 291 * simply create the intarr. 292 */ 293 i = 0; 294 while (strptr[i] != 46) { 295 if (strptr[i] == 0) { 296 no_dec = 1; 297 break; 298 } 299 intarr[i] = strptr[i]; 300 i++; 301 } 302 303 /* Assign length of integer part to intarr_len. */ 304 intarr_len = i; 305 intarr[i] = '\0'; 306 307 if (no_dec) { 308 /* Currently needed only for single digit corepll ratios */ 309 mulconst = 10; 310 decval = 0; 311 } else { 312 j = 0; 313 i++; /* Skipping the decimal point */ 314 while ((strptr[i] > 47) && (strptr[i] < 58)) { 315 decarr[j] = strptr[i]; 316 i++; 317 j++; 318 } 319 320 decarr_len = j; 321 decarr[j] = '\0'; 322 323 mulconst = 1; 324 for (i = 0; i < decarr_len; i++) 325 mulconst *= 10; 326 decval = simple_strtoul((char *)decarr, NULL, 10); 327 } 328 329 intval = simple_strtoul((char *)intarr, NULL, 10); 330 intval = intval * mulconst; 331 332 retval = intval + decval; 333 334 return retval; 335 } 336 337 338 int 339 pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 340 { 341 ulong val; 342 ulong corepll; 343 344 /* 345 * No args is a simple reset request. 346 */ 347 if (argc <= 1) { 348 pixis_reset(); 349 /* not reached */ 350 } 351 352 if (strcmp(argv[1], "cf") == 0) { 353 354 /* 355 * Reset with frequency changed: 356 * cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio> 357 */ 358 if (argc < 5) { 359 puts(cmdtp->usage); 360 return 1; 361 } 362 363 read_from_px_regs(0); 364 365 val = set_px_sysclk(simple_strtoul(argv[2], NULL, 10)); 366 367 corepll = strfractoint((uchar *)argv[3]); 368 val = val + set_px_corepll(corepll); 369 val = val + set_px_mpxpll(simple_strtoul(argv[4], NULL, 10)); 370 if (val == 3) { 371 puts("Setting registers VCFGEN0 and VCTL\n"); 372 read_from_px_regs(1); 373 puts("Resetting board with values from "); 374 puts("VSPEED0, VSPEED1, VCLKH, and VCLKL \n"); 375 set_px_go(); 376 } else { 377 puts(cmdtp->usage); 378 return 1; 379 } 380 381 while (1) ; /* Not reached */ 382 383 } else if (strcmp(argv[1], "altbank") == 0) { 384 385 /* 386 * Reset using alternate flash bank: 387 */ 388 if (argv[2] == 0) { 389 /* 390 * Reset from alternate bank without changing 391 * frequency and without watchdog timer enabled. 392 * altbank 393 */ 394 read_from_px_regs(0); 395 read_from_px_regs_altbank(0); 396 if (argc > 2) { 397 puts(cmdtp->usage); 398 return 1; 399 } 400 puts("Setting registers VCFGNE1, VBOOT, and VCTL\n"); 401 set_altbank(); 402 read_from_px_regs_altbank(1); 403 puts("Resetting board to boot from the other bank.\n"); 404 set_px_go(); 405 406 } else if (strcmp(argv[2], "cf") == 0) { 407 /* 408 * Reset with frequency changed 409 * altbank cf <SYSCLK freq> <COREPLL ratio> 410 * <MPXPLL ratio> 411 */ 412 read_from_px_regs(0); 413 read_from_px_regs_altbank(0); 414 val = set_px_sysclk(simple_strtoul(argv[3], NULL, 10)); 415 corepll = strfractoint((uchar *)argv[4]); 416 val = val + set_px_corepll(corepll); 417 val = val + set_px_mpxpll(simple_strtoul(argv[5], 418 NULL, 10)); 419 if (val == 3) { 420 puts("Setting registers VCFGEN0, VCFGEN1, VBOOT, and VCTL\n"); 421 set_altbank(); 422 read_from_px_regs(1); 423 read_from_px_regs_altbank(1); 424 puts("Enabling watchdog timer on the FPGA\n"); 425 puts("Resetting board with values from "); 426 puts("VSPEED0, VSPEED1, VCLKH and VCLKL "); 427 puts("to boot from the other bank.\n"); 428 set_px_go_with_watchdog(); 429 } else { 430 puts(cmdtp->usage); 431 return 1; 432 } 433 434 while (1) ; /* Not reached */ 435 436 } else if (strcmp(argv[2], "wd") == 0) { 437 /* 438 * Reset from alternate bank without changing 439 * frequencies but with watchdog timer enabled: 440 * altbank wd 441 */ 442 read_from_px_regs(0); 443 read_from_px_regs_altbank(0); 444 puts("Setting registers VCFGEN1, VBOOT, and VCTL\n"); 445 set_altbank(); 446 read_from_px_regs_altbank(1); 447 puts("Enabling watchdog timer on the FPGA\n"); 448 puts("Resetting board to boot from the other bank.\n"); 449 set_px_go_with_watchdog(); 450 while (1) ; /* Not reached */ 451 452 } else { 453 puts(cmdtp->usage); 454 return 1; 455 } 456 457 } else { 458 puts(cmdtp->usage); 459 return 1; 460 } 461 462 return 0; 463 } 464 465 466 U_BOOT_CMD( 467 pixis_reset, CFG_MAXARGS, 1, pixis_reset_cmd, 468 "pixis_reset - Reset the board using the FPGA sequencer\n", 469 " pixis_reset\n" 470 " pixis_reset [altbank]\n" 471 " pixis_reset altbank wd\n" 472 " pixis_reset altbank cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n" 473 " pixis_reset cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n" 474 ); 475 #endif /* CONFIG_FSL_PIXIS */ 476