blob: b0fe8abb2c34a612156096711466e3870b3fb5d7 [file] [log] [blame]
Jon Loeligerdebb7352006-04-26 17:58:56 -05001/*
2 * Copyright 2004 Freescale Semiconductor
3 * Jeff Brown (jeffrey@freescale.com)
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 <watchdog.h>
27#include <command.h>
28#include <asm/cache.h>
29#include <mpc86xx.h>
30
31#if defined(CONFIG_OF_FLAT_TREE)
32#include <ft_build.h>
33#endif
34
35
36// SS: For debug only, remove after use
37
38static __inline__ unsigned long get_dbat3u (void)
39{
40 unsigned long dbat3u;
41 asm volatile("mfspr %0, 542" : "=r" (dbat3u) :);
42 return dbat3u;
43}
44
45static __inline__ unsigned long get_dbat3l (void)
46{
47 unsigned long dbat3l;
48 asm volatile("mfspr %0, 543" : "=r" (dbat3l) :);
49 return dbat3l;
50}
51
52static __inline__ unsigned long get_msr (void)
53{
54 unsigned long msr;
55 asm volatile("mfmsr %0" : "=r" (msr) :);
56 return msr;
57}
58
59extern unsigned long get_board_sys_clk(ulong dummy);
60
61int checkcpu (void)
62{
63 sys_info_t sysinfo;
64 uint pvr, svr;
65 uint ver;
66 uint major, minor;
67 uint lcrr; /* local bus clock ratio register */
68 uint clkdiv; /* clock divider portion of lcrr */
69
70 puts("Freescale PowerPC\n");
71
72 pvr = get_pvr();
73 ver = PVR_VER(pvr);
74 major = PVR_MAJ(pvr);
75 minor = PVR_MIN(pvr);
76
77 puts ("CPU:\n");
78
79 printf(" Core: ");
80
81 switch (ver) {
82 case PVR_VER(PVR_86xx):
83 puts("E600");
84 break;
85 default:
86 puts("Unknown");
87 break;
88 }
89 printf(", Version: %d.%d, (0x%08x)\n", major, minor, pvr);
90
91 svr = get_svr();
92 ver = SVR_VER(svr);
93 major = SVR_MAJ(svr);
94 minor = SVR_MIN(svr);
95
96 puts(" System: ");
97 switch (ver) {
98 case SVR_8641:
99 puts("8641");
100 break;
101 case SVR_8641D:
102 puts("8641D");
103 break;
104 default:
105 puts("Unknown");
106 break;
107 }
108 printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr);
109
110 get_sys_info(&sysinfo);
111
112 puts(" Clocks: ");
113 printf("CPU:%4lu MHz, ", sysinfo.freqProcessor / 1000000);
114 printf("MPX:%4lu MHz, ", sysinfo.freqSystemBus / 1000000);
115 printf("DDR:%4lu MHz, ", sysinfo.freqSystemBus / 2000000);
116
117#if defined(CFG_LBC_LCRR)
118 lcrr = CFG_LBC_LCRR;
119#else
120 {
121 volatile immap_t *immap = (immap_t *)CFG_IMMR;
122 volatile ccsr_lbc_t *lbc= &immap->im_lbc;
123
124 lcrr = lbc->lcrr;
125 }
126#endif
127 clkdiv = lcrr & 0x0f;
128 if (clkdiv == 2 || clkdiv == 4 || clkdiv == 8) {
129 printf("LBC:%4lu MHz\n",
130 sysinfo.freqSystemBus / 1000000 / clkdiv);
131 } else {
132 printf(" LBC: unknown (lcrr: 0x%08x)\n", lcrr);
133 }
134
135 printf(" L2: ");
136 if (get_l2cr() & 0x80000000)
137 printf("Enabled\n");
138 else
139 printf("Disabled\n");
140
141 return (0);
142}
143
144
145/* -------------------------------------------------------------------- */
146
147static inline void
148soft_restart(unsigned long addr)
149{
150
151#ifndef CONFIG_MPC8641HPCN
152
153 /* SRR0 has system reset vector, SRR1 has default MSR value */
154 /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
155
156 __asm__ __volatile__ ("mtspr 26, %0" :: "r" (addr));
157 __asm__ __volatile__ ("li 4, (1 << 6)" ::: "r4");
158 __asm__ __volatile__ ("mtspr 27, 4");
159 __asm__ __volatile__ ("rfi");
160
161#else /* CONFIG_MPC8641HPCN */
162 out8(PIXIS_BASE+PIXIS_RST,0);
163#endif /* !CONFIG_MPC8641HPCN */
164 while(1); /* not reached */
165}
166
167
168
169#ifdef CONFIG_MPC8641HPCN
170
171int set_px_sysclk(ulong sysclk)
172{
173 u8 sysclk_s, sysclk_r, sysclk_v, vclkh, vclkl, sysclk_aux,tmp;
174
175 /* Per table 27, page 58 of MPC8641HPCN spec*/
176 switch(sysclk)
177 {
178 case 33:
179 sysclk_s = 0x04;
180 sysclk_r = 0x04;
181 sysclk_v = 0x07;
182 sysclk_aux = 0x00;
183 break;
184 case 40:
185 sysclk_s = 0x01;
186 sysclk_r = 0x1F;
187 sysclk_v = 0x20;
188 sysclk_aux = 0x01;
189 break;
190 case 50:
191 sysclk_s = 0x01;
192 sysclk_r = 0x1F;
193 sysclk_v = 0x2A;
194 sysclk_aux = 0x02;
195 break;
196 case 66:
197 sysclk_s = 0x01;
198 sysclk_r = 0x04;
199 sysclk_v = 0x04;
200 sysclk_aux = 0x03;
201 break;
202 case 83:
203 sysclk_s = 0x01;
204 sysclk_r = 0x1F;
205 sysclk_v = 0x4B;
206 sysclk_aux = 0x04;
207 break;
208 case 100:
209 sysclk_s = 0x01;
210 sysclk_r = 0x1F;
211 sysclk_v = 0x5C;
212 sysclk_aux = 0x05;
213 break;
214 case 134:
215 sysclk_s = 0x06;
216 sysclk_r = 0x1F;
217 sysclk_v = 0x3B;
218 sysclk_aux = 0x06;
219 break;
220 case 166:
221 sysclk_s = 0x06;
222 sysclk_r = 0x1F;
223 sysclk_v = 0x4B;
224 sysclk_aux = 0x07;
225 break;
226 default:
227 printf("Unsupported SYSCLK frequency.\n");
228 return 0;
229 }
230
231 vclkh = (sysclk_s << 5) | sysclk_r ;
232 vclkl = sysclk_v;
233 out8(PIXIS_BASE+PIXIS_VCLKH,vclkh);
234 out8(PIXIS_BASE+PIXIS_VCLKL,vclkl);
235
236 out8(PIXIS_BASE+PIXIS_AUX,sysclk_aux);
237
238 return 1;
239}
240
241int set_px_mpxpll(ulong mpxpll)
242{
243 u8 tmp;
244 u8 val;
245 switch(mpxpll)
246 {
247 case 2:
248 case 4:
249 case 6:
250 case 8:
251 case 10:
252 case 12:
253 case 14:
254 case 16:
255 val = (u8)mpxpll;
256 break;
257 default:
258 printf("Unsupported MPXPLL ratio.\n");
259 return 0;
260 }
261
262 tmp = in8(PIXIS_BASE+PIXIS_VSPEED1);
263 tmp = (tmp & 0xF0) | (val & 0x0F);
264 out8(PIXIS_BASE+PIXIS_VSPEED1,tmp);
265
266 return 1;
267}
268
269int set_px_corepll(ulong corepll)
270{
271 u8 tmp;
272 u8 val;
273
274 switch((int)corepll)
275 {
276 case 20:
277 val = 0x08;
278 break;
279 case 25:
280 val = 0x0C;
281 break;
282 case 30:
283 val = 0x10;
284 break;
285 case 35:
286 val = 0x1C;
287 break;
288 case 40:
289 val = 0x14;
290 break;
291 case 45:
292 val = 0x0E;
293 break;
294 default:
295 printf("Unsupported COREPLL ratio.\n");
296 return 0;
297 }
298
299 tmp = in8(PIXIS_BASE+PIXIS_VSPEED0);
300 tmp = (tmp & 0xE0) | (val & 0x1F);
301 out8(PIXIS_BASE+PIXIS_VSPEED0,tmp);
302
303 return 1;
304}
305
306void read_from_px_regs(int set)
307{
308 u8 tmp, mask = 0x1C;
309 tmp = in8(PIXIS_BASE+PIXIS_VCFGEN0);
310 if (set)
311 tmp = tmp | mask;
312 else
313 tmp = tmp & ~mask;
314 out8(PIXIS_BASE+PIXIS_VCFGEN0,tmp);
315}
316
317void read_from_px_regs_altbank(int set)
318{
319 u8 tmp, mask = 0x04;
320 tmp = in8(PIXIS_BASE+PIXIS_VCFGEN1);
321 if (set)
322 tmp = tmp | mask;
323 else
324 tmp = tmp & ~mask;
325 out8(PIXIS_BASE+PIXIS_VCFGEN1,tmp);
326}
327
328void set_altbank(void)
329{
330 u8 tmp;
331 tmp = in8(PIXIS_BASE+PIXIS_VBOOT);
332 tmp ^= 0x40;
333 out8(PIXIS_BASE+PIXIS_VBOOT,tmp);
334 }
335
336
337void set_px_go(void)
338{
339 u8 tmp;
340 tmp = in8(PIXIS_BASE+PIXIS_VCTL);
341 tmp = tmp & 0x1E;
342 out8(PIXIS_BASE+PIXIS_VCTL,tmp);
343 tmp = in8(PIXIS_BASE+PIXIS_VCTL);
344 tmp = tmp | 0x01;
345 out8(PIXIS_BASE+PIXIS_VCTL,tmp);
346}
347
348void set_px_go_with_watchdog(void)
349{
350 u8 tmp;
351 tmp = in8(PIXIS_BASE+PIXIS_VCTL);
352 tmp = tmp & 0x1E;
353 out8(PIXIS_BASE+PIXIS_VCTL,tmp);
354 tmp = in8(PIXIS_BASE+PIXIS_VCTL);
355 tmp = tmp | 0x09;
356 out8(PIXIS_BASE+PIXIS_VCTL,tmp);
357}
358
359/* This function takes the non-integral cpu:mpx pll ratio
360 * and converts it to an integer that can be used to assign
361 * FPGA register values.
362 * input: strptr i.e. argv[2]
363*/
364
365ulong strfractoint(uchar *strptr)
366{
367 int i,j,retval,intarr_len=0, decarr_len=0, mulconst, no_dec=0;
368 ulong intval =0, decval=0;
369 uchar intarr[3], decarr[3];
370
371 /* Assign the integer part to intarr[]
372 * If there is no decimal point i.e.
373 * if the ratio is an integral value
374 * simply create the intarr.
375 */
376 i=0;
377 while(strptr[i] != 46)
378 {
379 if(strptr[i] == 0)
380 {
381 no_dec = 1;
382 break; /* Break from loop once the end of string is reached */
383 }
384
385 intarr[i] = strptr[i];
386 i++;
387 }
388
389 intarr_len = i; /* Assign length of integer part to intarr_len*/
390 intarr[i] = '\0'; /* */
391
392 if(no_dec)
393 {
394 mulconst=10; /* Currently needed only for single digit corepll ratios */
395 decval = 0;
396 }
397 else
398 {
399 j=0;
400 i++; /* Skipping the decimal point */
401 while ((strptr[i] > 47) && (strptr[i] < 58))
402 {
403 decarr[j] = strptr[i];
404 i++;
405 j++;
406 }
407
408 decarr_len = j;
409 decarr[j] = '\0';
410
411 mulconst=1;
412 for(i=0; i<decarr_len;i++)
413 mulconst = mulconst*10;
414 decval = simple_strtoul(decarr,NULL,10);
415 }
416
417 intval = simple_strtoul(intarr,NULL,10);
418 intval = intval*mulconst;
419
420 retval = intval+decval;
421
422 return retval;
423
424}
425
426
427#endif //CONFIG_MPC8641HPCN
428
429
430/* no generic way to do board reset. simply call soft_reset. */
431void
432do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
433{
434 char cmd;
435 ulong addr, val;
436 ulong corepll;
437
438
439
440#ifdef CFG_RESET_ADDRESS
441 addr = CFG_RESET_ADDRESS;
442#else
443 /*
444 * note: when CFG_MONITOR_BASE points to a RAM address,
445 * CFG_MONITOR_BASE - sizeof (ulong) is usually a valid
446 * address. Better pick an address known to be invalid on your
447 * system and assign it to CFG_RESET_ADDRESS.
448 */
449 addr = CFG_MONITOR_BASE - sizeof (ulong);
450#endif
451
452#ifndef CONFIG_MPC8641HPCN
453
454 /* flush and disable I/D cache */
455 __asm__ __volatile__ ("mfspr 3, 1008" ::: "r3");
456 __asm__ __volatile__ ("ori 5, 5, 0xcc00" ::: "r5");
457 __asm__ __volatile__ ("ori 4, 3, 0xc00" ::: "r4");
458 __asm__ __volatile__ ("andc 5, 3, 5" ::: "r5");
459 __asm__ __volatile__ ("sync");
460 __asm__ __volatile__ ("mtspr 1008, 4");
461 __asm__ __volatile__ ("isync");
462 __asm__ __volatile__ ("sync");
463 __asm__ __volatile__ ("mtspr 1008, 5");
464 __asm__ __volatile__ ("isync");
465 __asm__ __volatile__ ("sync");
466
467 soft_restart(addr);
468
469#else /* CONFIG_MPC8641HPCN */
470
471 if(argc > 1)
472 {
473 cmd = argv[1][1];
474 switch(cmd)
475 {
476 case 'f': /* reset with frequency changed */
477
478 if (argc < 5)
479 goto my_usage;
480
481 read_from_px_regs(0);
482
483 val = set_px_sysclk(simple_strtoul(argv[2],NULL,10));
484
485 corepll = strfractoint(argv[3]);
486 val = val + set_px_corepll(corepll);
487 val = val + set_px_mpxpll(simple_strtoul(argv[4],NULL,10));
488 if(val == 3)
489 {
490 printf("Setting registers VCFGEN0 and VCTL\n");
491 read_from_px_regs(1);
492 printf("Resetting board with values from VSPEED0, VSPEED1, VCLKH, and VCLKL ....\n");
493 set_px_go();
494 }
495 else
496 goto my_usage;
497
498 while(1); /* Not reached */
499
500 case 'l':
501 if(argv[2][1] == 'f')
502 {
503 read_from_px_regs(0);
504 read_from_px_regs_altbank(0);
505 /* reset with frequency changed */
506 val = set_px_sysclk(simple_strtoul(argv[3],NULL,10));
507
508 corepll = strfractoint(argv[4]);
509 val = val + set_px_corepll(corepll);
510 val = val + set_px_mpxpll(simple_strtoul(argv[5],NULL,10));
511 if(val == 3)
512 {
513 printf("Setting registers VCFGEN0, VCFGEN1, VBOOT, and VCTL\n");
514 set_altbank();
515 read_from_px_regs(1);
516 read_from_px_regs_altbank(1);
517 printf("Enabling watchdog timer on the FPGA and resetting board with values from VSPEED0, VSPEED1, VCLKH, and VCLKL to boot from the other bank ....\n");
518 set_px_go_with_watchdog();
519
520 }
521 else
522 goto my_usage;
523
524 while(1); /* Not reached */
525 }
526 else /* Reset from next bank without changing frequencies */
527 {
528 read_from_px_regs(0);
529 read_from_px_regs_altbank(0);
530 if(argc > 2)
531 goto my_usage;
532 printf("Setting registers VCFGEN1, VBOOT, and VCTL\n");
533 set_altbank();
534 read_from_px_regs_altbank(1);
535 printf("Enabling watchdog timer on the FPGA and resetting board to boot from the other bank....\n");
536 set_px_go_with_watchdog();
537 while(1); /* Not reached */
538 }
539
540 default:
541 goto my_usage;
542 }
543my_usage:
544 printf("\nUsage: reset cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n");
545 printf(" reset altbank [cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>]\n");
546 printf("For example: reset cf 40 2.5 10\n");
547 printf("See MPC8641HPCN Design Workbook for valid values of command line parameters.\n");
548 return;
549 }
550 else
551 out8(PIXIS_BASE+PIXIS_RST,0);
552
553#endif /* !CONFIG_MPC8641HPCN */
554
555 while(1); /* not reached */
556}
557
558
559/* ------------------------------------------------------------------------- */
560
561/*
562 * Get timebase clock frequency
563 */
564unsigned long get_tbclk(void)
565{
566 sys_info_t sys_info;
567
568 get_sys_info(&sys_info);
569 return ((sys_info.freqSystemBus + 3L) / 4L);
570
571}
572
573/* ------------------------------------------------------------------------- */
574
575#if defined(CONFIG_WATCHDOG)
576void
577watchdog_reset(void)
578{
579
580}
581#endif /* CONFIG_WATCHDOG */
582
583/* ------------------------------------------------------------------------- */
584
585#if defined(CONFIG_DDR_ECC)
586void dma_init(void) {
587 volatile immap_t *immap = (immap_t *)CFG_IMMR;
588 volatile ccsr_dma_t *dma = &immap->im_dma;
589
590 dma->satr0 = 0x00040000;
591 dma->datr0 = 0x00040000;
592 asm("sync; isync");
593 return;
594}
595
596uint dma_check(void) {
597 volatile immap_t *immap = (immap_t *)CFG_IMMR;
598 volatile ccsr_dma_t *dma = &immap->im_dma;
599 volatile uint status = dma->sr0;
600
601 /* While the channel is busy, spin */
602 while((status & 4) == 4) {
603 status = dma->sr0;
604 }
605
606 if (status != 0) {
607 printf ("DMA Error: status = %x\n", status);
608 }
609 return status;
610}
611
612int dma_xfer(void *dest, uint count, void *src) {
613 volatile immap_t *immap = (immap_t *)CFG_IMMR;
614 volatile ccsr_dma_t *dma = &immap->im_dma;
615
616 dma->dar0 = (uint) dest;
617 dma->sar0 = (uint) src;
618 dma->bcr0 = count;
619 dma->mr0 = 0xf000004;
620 asm("sync;isync");
621 dma->mr0 = 0xf000005;
622 asm("sync;isync");
623 return dma_check();
624}
625#endif /* CONFIG_DDR_ECC */
626
627
628#ifdef CONFIG_OF_FLAT_TREE
629void ft_cpu_setup(void *blob, bd_t *bd)
630{
631 u32 *p;
632 ulong clock;
633 int len;
634
635 clock = bd->bi_busfreq;
636 p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len);
637 if (p != NULL)
638 *p = cpu_to_be32(clock);
639
640 p = ft_get_prop(blob, "/" OF_SOC "/serial@4500/clock-frequency", &len);
641 if (p != NULL)
642 *p = cpu_to_be32(clock);
643
644 p = ft_get_prop(blob, "/" OF_SOC "/serial@4600/clock-frequency", &len);
645 if (p != NULL)
646 *p = cpu_to_be32(clock);
647
648#if defined(CONFIG_MPC86XX_TSEC1)
649 p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/address", &len);
650 memcpy(p, bd->bi_enetaddr, 6);
651#endif
652
653#if defined(CONFIG_MPC86XX_TSEC2)
654 p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/address", &len);
655 memcpy(p, bd->bi_enet1addr, 6);
656#endif
657
658#if defined(CONFIG_MPC86XX_TSEC3)
659 p = ft_get_prop(blob, "/" OF_SOC "/ethernet@26000/address", &len);
660 memcpy(p, bd->bi_enet2addr, 6);
661#endif
662
663#if defined(CONFIG_MPC86XX_TSEC4)
664 p = ft_get_prop(blob, "/" OF_SOC "/ethernet@27000/address", &len);
665 memcpy(p, bd->bi_enet3addr, 6);
666#endif
667
668}
669#endif