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