]> git.sur5r.net Git - u-boot/blob - cpu/mpc86xx/cpu.c
b0fe8abb2c34a612156096711466e3870b3fb5d7
[u-boot] / cpu / mpc86xx / cpu.c
1 /*
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
38 static __inline__ unsigned long get_dbat3u (void)
39 {
40    unsigned long dbat3u;
41    asm volatile("mfspr %0, 542" : "=r" (dbat3u) :);
42    return dbat3u;
43 }
44
45 static __inline__ unsigned long get_dbat3l (void)
46 {
47    unsigned long dbat3l;
48    asm volatile("mfspr %0, 543" : "=r" (dbat3l) :);
49    return dbat3l;
50 }
51
52 static __inline__ unsigned long get_msr (void)
53 {
54    unsigned long msr;
55    asm volatile("mfmsr %0" : "=r" (msr) :);
56    return msr;
57 }
58
59 extern unsigned long get_board_sys_clk(ulong dummy);
60
61 int 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
147 static inline void
148 soft_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
171 int 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
241 int 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
269 int 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
306 void 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
317 void 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
328 void 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
337 void 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
348 void 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
365 ulong 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. */
431 void
432 do_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            }
543 my_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  */
564 unsigned 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)
576 void
577 watchdog_reset(void)
578 {
579
580 }
581 #endif  /* CONFIG_WATCHDOG */
582
583 /* ------------------------------------------------------------------------- */
584
585 #if defined(CONFIG_DDR_ECC)
586 void 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
596 uint 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
612 int 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
629 void 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