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