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; /* COREPLL, MPXPLL, SYSCLK controlled by PIXIS */ 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; /* FLASHBANK and FLASHMAP controlled by PIXIS */ 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 #ifndef CFG_PIXIS_VBOOT_MASK 210 #define CFG_PIXIS_VBOOT_MASK (0x40) 211 #endif 212 213 void clear_altbank(void) 214 { 215 u8 tmp; 216 217 tmp = in8(PIXIS_BASE + PIXIS_VBOOT); 218 tmp &= ~CFG_PIXIS_VBOOT_MASK; 219 220 out8(PIXIS_BASE + PIXIS_VBOOT, tmp); 221 } 222 223 224 void set_altbank(void) 225 { 226 u8 tmp; 227 228 tmp = in8(PIXIS_BASE + PIXIS_VBOOT); 229 tmp |= CFG_PIXIS_VBOOT_MASK; 230 231 out8(PIXIS_BASE + PIXIS_VBOOT, tmp); 232 } 233 234 235 void set_px_go(void) 236 { 237 u8 tmp; 238 239 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 240 tmp = tmp & 0x1E; /* clear GO bit */ 241 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 242 243 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 244 tmp = tmp | 0x01; /* set GO bit - start reset sequencer */ 245 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 246 } 247 248 249 void set_px_go_with_watchdog(void) 250 { 251 u8 tmp; 252 253 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 254 tmp = tmp & 0x1E; 255 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 256 257 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 258 tmp = tmp | 0x09; 259 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 260 } 261 262 263 int pixis_disable_watchdog_cmd(cmd_tbl_t *cmdtp, 264 int flag, int argc, char *argv[]) 265 { 266 u8 tmp; 267 268 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 269 tmp = tmp & 0x1E; 270 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 271 272 /* setting VCTL[WDEN] to 0 to disable watch dog */ 273 tmp = in8(PIXIS_BASE + PIXIS_VCTL); 274 tmp &= ~0x08; 275 out8(PIXIS_BASE + PIXIS_VCTL, tmp); 276 277 return 0; 278 } 279 280 U_BOOT_CMD( 281 diswd, 1, 0, pixis_disable_watchdog_cmd, 282 "diswd - Disable watchdog timer \n", 283 NULL); 284 285 /* 286 * This function takes the non-integral cpu:mpx pll ratio 287 * and converts it to an integer that can be used to assign 288 * FPGA register values. 289 * input: strptr i.e. argv[2] 290 */ 291 292 static ulong strfractoint(uchar *strptr) 293 { 294 int i, j, retval; 295 int mulconst; 296 int intarr_len = 0, decarr_len = 0, no_dec = 0; 297 ulong intval = 0, decval = 0; 298 uchar intarr[3], decarr[3]; 299 300 /* Assign the integer part to intarr[] 301 * If there is no decimal point i.e. 302 * if the ratio is an integral value 303 * simply create the intarr. 304 */ 305 i = 0; 306 while (strptr[i] != '.') { 307 if (strptr[i] == 0) { 308 no_dec = 1; 309 break; 310 } 311 intarr[i] = strptr[i]; 312 i++; 313 } 314 315 /* Assign length of integer part to intarr_len. */ 316 intarr_len = i; 317 intarr[i] = '\0'; 318 319 if (no_dec) { 320 /* Currently needed only for single digit corepll ratios */ 321 mulconst = 10; 322 decval = 0; 323 } else { 324 j = 0; 325 i++; /* Skipping the decimal point */ 326 while ((strptr[i] >= '0') && (strptr[i] <= '9')) { 327 decarr[j] = strptr[i]; 328 i++; 329 j++; 330 } 331 332 decarr_len = j; 333 decarr[j] = '\0'; 334 335 mulconst = 1; 336 for (i = 0; i < decarr_len; i++) 337 mulconst *= 10; 338 decval = simple_strtoul((char *)decarr, NULL, 10); 339 } 340 341 intval = simple_strtoul((char *)intarr, NULL, 10); 342 intval = intval * mulconst; 343 344 retval = intval + decval; 345 346 return retval; 347 } 348 349 350 int 351 pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 352 { 353 unsigned int i; 354 char *p_cf = NULL; 355 char *p_cf_sysclk = NULL; 356 char *p_cf_corepll = NULL; 357 char *p_cf_mpxpll = NULL; 358 char *p_altbank = NULL; 359 char *p_wd = NULL; 360 unsigned int unknown_param = 0; 361 362 /* 363 * No args is a simple reset request. 364 */ 365 if (argc <= 1) { 366 pixis_reset(); 367 /* not reached */ 368 } 369 370 for (i = 1; i < argc; i++) { 371 if (strcmp(argv[i], "cf") == 0) { 372 p_cf = argv[i]; 373 if (i + 3 >= argc) { 374 break; 375 } 376 p_cf_sysclk = argv[i+1]; 377 p_cf_corepll = argv[i+2]; 378 p_cf_mpxpll = argv[i+3]; 379 i += 3; 380 continue; 381 } 382 383 if (strcmp(argv[i], "altbank") == 0) { 384 p_altbank = argv[i]; 385 continue; 386 } 387 388 if (strcmp(argv[i], "wd") == 0) { 389 p_wd = argv[i]; 390 continue; 391 } 392 393 unknown_param = 1; 394 } 395 396 /* 397 * Check that cf has all required parms 398 */ 399 if ((p_cf && !(p_cf_sysclk && p_cf_corepll && p_cf_mpxpll)) 400 || unknown_param) { 401 puts(cmdtp->help); 402 return 1; 403 } 404 405 /* 406 * PIXIS seems to be sensitive to the ordering of 407 * the registers that are touched. 408 */ 409 read_from_px_regs(0); 410 411 if (p_altbank) { 412 read_from_px_regs_altbank(0); 413 } 414 clear_altbank(); 415 416 /* 417 * Clock configuration specified. 418 */ 419 if (p_cf) { 420 unsigned long sysclk; 421 unsigned long corepll; 422 unsigned long mpxpll; 423 424 sysclk = simple_strtoul(p_cf_sysclk, NULL, 10); 425 corepll = strfractoint((uchar *) p_cf_corepll); 426 mpxpll = simple_strtoul(p_cf_mpxpll, NULL, 10); 427 428 if (!(set_px_sysclk(sysclk) 429 && set_px_corepll(corepll) 430 && set_px_mpxpll(mpxpll))) { 431 puts(cmdtp->help); 432 return 1; 433 } 434 read_from_px_regs(1); 435 } 436 437 /* 438 * Altbank specified 439 * 440 * NOTE CHANGE IN BEHAVIOR: previous code would default 441 * to enabling watchdog if altbank is specified. 442 * Now the watchdog must be enabled explicitly using 'wd'. 443 */ 444 if (p_altbank) { 445 set_altbank(); 446 read_from_px_regs_altbank(1); 447 } 448 449 /* 450 * Reset with watchdog specified. 451 */ 452 if (p_wd) { 453 set_px_go_with_watchdog(); 454 } else { 455 set_px_go(); 456 } 457 458 /* 459 * Shouldn't be reached. 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