mpc83xx: Recognize SPR values for MPC8311 and MPC8313.
[oweals/u-boot.git] / cpu / mpc83xx / cpu.c
1 /*
2  * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22
23 /*
24  * CPU specific code for the MPC83xx family.
25  *
26  * Derived from the MPC8260 and MPC85xx.
27  */
28
29 #include <common.h>
30 #include <watchdog.h>
31 #include <command.h>
32 #include <mpc83xx.h>
33 #include <asm/processor.h>
34 #if defined(CONFIG_OF_FLAT_TREE)
35 #include <ft_build.h>
36 #endif
37 #if defined(CONFIG_OF_LIBFDT)
38 #include <libfdt.h>
39 #include <libfdt_env.h>
40 #endif
41
42 DECLARE_GLOBAL_DATA_PTR;
43
44
45 int checkcpu(void)
46 {
47         volatile immap_t *immr;
48         ulong clock = gd->cpu_clk;
49         u32 pvr = get_pvr();
50         u32 spridr;
51         char buf[32];
52
53         immr = (immap_t *)CFG_IMMR;
54
55         if ((pvr & 0xFFFF0000) != PVR_83xx) {
56                 puts("Not MPC83xx Family!!!\n");
57                 return -1;
58         }
59
60         spridr = immr->sysconf.spridr;
61         puts("CPU: ");
62         switch(spridr) {
63         case SPR_8349E_REV10:
64         case SPR_8349E_REV11:
65         case SPR_8349E_REV31:
66                 puts("MPC8349E, ");
67                 break;
68         case SPR_8349_REV10:
69         case SPR_8349_REV11:
70         case SPR_8349_REV31:
71                 puts("MPC8349, ");
72                 break;
73         case SPR_8347E_REV10_TBGA:
74         case SPR_8347E_REV11_TBGA:
75         case SPR_8347E_REV31_TBGA:
76         case SPR_8347E_REV10_PBGA:
77         case SPR_8347E_REV11_PBGA:
78         case SPR_8347E_REV31_PBGA:
79                 puts("MPC8347E, ");
80                 break;
81         case SPR_8347_REV10_TBGA:
82         case SPR_8347_REV11_TBGA:
83         case SPR_8347_REV31_TBGA:
84         case SPR_8347_REV10_PBGA:
85         case SPR_8347_REV11_PBGA:
86         case SPR_8347_REV31_PBGA:
87                 puts("MPC8347, ");
88                 break;
89         case SPR_8343E_REV10:
90         case SPR_8343E_REV11:
91         case SPR_8343E_REV31:
92                 puts("MPC8343E, ");
93                 break;
94         case SPR_8343_REV10:
95         case SPR_8343_REV11:
96         case SPR_8343_REV31:
97                 puts("MPC8343, ");
98                 break;
99         case SPR_8360E_REV10:
100         case SPR_8360E_REV11:
101         case SPR_8360E_REV12:
102         case SPR_8360E_REV20:
103                 puts("MPC8360E, ");
104                 break;
105         case SPR_8360_REV10:
106         case SPR_8360_REV11:
107         case SPR_8360_REV12:
108         case SPR_8360_REV20:
109                 puts("MPC8360, ");
110                 break;
111         case SPR_8323E_REV10:
112         case SPR_8323E_REV11:
113                 puts("MPC8323E, ");
114                 break;
115         case SPR_8323_REV10:
116         case SPR_8323_REV11:
117                 puts("MPC8323, ");
118                 break;
119         case SPR_8321E_REV10:
120         case SPR_8321E_REV11:
121                 puts("MPC8321E, ");
122                 break;
123         case SPR_8321_REV10:
124         case SPR_8321_REV11:
125                 puts("MPC8321, ");
126                 break;
127         case SPR_8311_REV10:
128                 puts("MPC8311, ");
129                 break;
130         case SPR_8311E_REV10:
131                 puts("MPC8311E, ");
132                 break;
133         case SPR_8313_REV10:
134                 puts("MPC8313, ");
135                 break;
136         case SPR_8313E_REV10:
137                 puts("MPC8313E, ");
138                 break;
139         default:
140                 puts("Rev: Unknown revision number.\nWarning: Unsupported cpu revision!\n");
141                 return 0;
142         }
143
144 #if defined(CONFIG_MPC834X)
145         /* Multiple revisons of 834x processors may have the same SPRIDR value.
146          * So use PVR to identify the revision number.
147          */
148         printf("Rev: %02x at %s MHz\n", PVR_MAJ(pvr)<<4 | PVR_MIN(pvr), strmhz(buf, clock));
149 #else
150         printf("Rev: %02x at %s MHz\n", spridr & 0x0000FFFF, strmhz(buf, clock));
151 #endif
152         return 0;
153 }
154
155
156 /*
157  * Program a UPM with the code supplied in the table.
158  *
159  * The 'dummy' variable is used to increment the MAD. 'dummy' is
160  * supposed to be a pointer to the memory of the device being
161  * programmed by the UPM.  The data in the MDR is written into
162  * memory and the MAD is incremented every time there's a read
163  * from 'dummy'. Unfortunately, the current prototype for this
164  * function doesn't allow for passing the address of this
165  * device, and changing the prototype will break a number lots
166  * of other code, so we need to use a round-about way of finding
167  * the value for 'dummy'.
168  *
169  * The value can be extracted from the base address bits of the
170  * Base Register (BR) associated with the specific UPM.  To find
171  * that BR, we need to scan all 8 BRs until we find the one that
172  * has its MSEL bits matching the UPM we want.  Once we know the
173  * right BR, we can extract the base address bits from it.
174  *
175  * The MxMR and the BR and OR of the chosen bank should all be
176  * configured before calling this function.
177  *
178  * Parameters:
179  * upm: 0=UPMA, 1=UPMB, 2=UPMC
180  * table: Pointer to an array of values to program
181  * size: Number of elements in the array.  Must be 64 or less.
182  */
183 void upmconfig (uint upm, uint *table, uint size)
184 {
185 #if defined(CONFIG_MPC834X)
186         volatile immap_t *immap = (immap_t *) CFG_IMMR;
187         volatile lbus83xx_t *lbus = &immap->lbus;
188         volatile uchar *dummy = NULL;
189         const u32 msel = (upm + 4) << BR_MSEL_SHIFT;    /* What the MSEL field in BRn should be */
190         volatile u32 *mxmr = &lbus->mamr + upm; /* Pointer to mamr, mbmr, or mcmr */
191         uint i;
192
193         /* Scan all the banks to determine the base address of the device */
194         for (i = 0; i < 8; i++) {
195                 if ((lbus->bank[i].br & BR_MSEL) == msel) {
196                         dummy = (uchar *) (lbus->bank[i].br & BR_BA);
197                         break;
198                 }
199         }
200
201         if (!dummy) {
202                 printf("Error: %s() could not find matching BR\n", __FUNCTION__);
203                 hang();
204         }
205
206         /* Set the OP field in the MxMR to "write" and the MAD field to 000000 */
207         *mxmr = (*mxmr & 0xCFFFFFC0) | 0x10000000;
208
209         for (i = 0; i < size; i++) {
210                 lbus->mdr = table[i];
211                 __asm__ __volatile__ ("sync");
212                 *dummy; /* Write the value to memory and increment MAD */
213                 __asm__ __volatile__ ("sync");
214         }
215
216         /* Set the OP field in the MxMR to "normal" and the MAD field to 000000 */
217         *mxmr &= 0xCFFFFFC0;
218 #else
219         printf("Error: %s() not defined for this configuration.\n", __FUNCTION__);
220         hang();
221 #endif
222 }
223
224
225 int
226 do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
227 {
228         ulong msr;
229 #ifndef MPC83xx_RESET
230         ulong addr;
231 #endif
232
233         volatile immap_t *immap = (immap_t *) CFG_IMMR;
234
235 #ifdef MPC83xx_RESET
236         /* Interrupts and MMU off */
237         __asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
238
239         msr &= ~( MSR_EE | MSR_IR | MSR_DR);
240         __asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
241
242         /* enable Reset Control Reg */
243         immap->reset.rpr = 0x52535445;
244         __asm__ __volatile__ ("sync");
245         __asm__ __volatile__ ("isync");
246
247         /* confirm Reset Control Reg is enabled */
248         while(!((immap->reset.rcer) & RCER_CRE));
249
250         printf("Resetting the board.");
251         printf("\n");
252
253         udelay(200);
254
255         /* perform reset, only one bit */
256         immap->reset.rcr = RCR_SWHR;
257
258 #else   /* ! MPC83xx_RESET */
259
260         immap->reset.rmr = RMR_CSRE;    /* Checkstop Reset enable */
261
262         /* Interrupts and MMU off */
263         __asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
264
265         msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
266         __asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
267
268         /*
269          * Trying to execute the next instruction at a non-existing address
270          * should cause a machine check, resulting in reset
271          */
272         addr = CFG_RESET_ADDRESS;
273
274         printf("resetting the board.");
275         printf("\n");
276         ((void (*)(void)) addr) ();
277 #endif  /* MPC83xx_RESET */
278
279         return 1;
280 }
281
282
283 /*
284  * Get timebase clock frequency (like cpu_clk in Hz)
285  */
286
287 unsigned long get_tbclk(void)
288 {
289         ulong tbclk;
290
291         tbclk = (gd->bus_clk + 3L) / 4L;
292
293         return tbclk;
294 }
295
296
297 #if defined(CONFIG_WATCHDOG)
298 void watchdog_reset (void)
299 {
300         int re_enable = disable_interrupts();
301
302         /* Reset the 83xx watchdog */
303         volatile immap_t *immr = (immap_t *) CFG_IMMR;
304         immr->wdt.swsrr = 0x556c;
305         immr->wdt.swsrr = 0xaa39;
306
307         if (re_enable)
308                 enable_interrupts ();
309 }
310 #endif
311
312 #if defined(CONFIG_OF_LIBFDT)
313
314 /*
315  * "Setter" functions used to add/modify FDT entries.
316  */
317 static int fdt_set_eth0(void *fdt, int nodeoffset, const char *name, bd_t *bd)
318 {
319         /*
320          * Fix it up if it exists, don't create it if it doesn't exist.
321          */
322         if (fdt_get_property(fdt, nodeoffset, name, 0)) {
323                 return fdt_setprop(fdt, nodeoffset, name, bd->bi_enetaddr, 6);
324         }
325         return -FDT_ERR_NOTFOUND;
326 }
327 #ifdef CONFIG_HAS_ETH1
328 /* second onboard ethernet port */
329 static int fdt_set_eth1(void *fdt, int nodeoffset, const char *name, bd_t *bd)
330 {
331         /*
332          * Fix it up if it exists, don't create it if it doesn't exist.
333          */
334         if (fdt_get_property(fdt, nodeoffset, name, 0)) {
335                 return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet1addr, 6);
336         }
337         return -FDT_ERR_NOTFOUND;
338 }
339 #endif
340 #ifdef CONFIG_HAS_ETH2
341 /* third onboard ethernet port */
342 static int fdt_set_eth2(void *fdt, int nodeoffset, const char *name, bd_t *bd)
343 {
344         /*
345          * Fix it up if it exists, don't create it if it doesn't exist.
346          */
347         if (fdt_get_property(fdt, nodeoffset, name, 0)) {
348                 return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet2addr, 6);
349         }
350         return -FDT_ERR_NOTFOUND;
351 }
352 #endif
353 #ifdef CONFIG_HAS_ETH3
354 /* fourth onboard ethernet port */
355 static int fdt_set_eth3(void *fdt, int nodeoffset, const char *name, bd_t *bd)
356 {
357         /*
358          * Fix it up if it exists, don't create it if it doesn't exist.
359          */
360         if (fdt_get_property(fdt, nodeoffset, name, 0)) {
361                 return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet3addr, 6);
362         }
363         return -FDT_ERR_NOTFOUND;
364 }
365 #endif
366
367 static int fdt_set_busfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd)
368 {
369         u32  tmp;
370         /*
371          * Create or update the property.
372          */
373         tmp = cpu_to_be32(bd->bi_busfreq);
374         return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
375 }
376
377 /*
378  * Fixups to the fdt.  If "create" is TRUE, the node is created
379  * unconditionally.  If "create" is FALSE, the node is updated
380  * only if it already exists.
381  */
382 static const struct {
383         char *node;
384         char *prop;
385         int (*set_fn)(void *fdt, int nodeoffset, const char *name, bd_t *bd);
386 } fixup_props[] = {
387         {       "/cpus/" OF_CPU,
388                  "bus-frequency",
389                 fdt_set_busfreq
390         },
391         {       "/cpus/" OF_SOC,
392                 "bus-frequency",
393                 fdt_set_busfreq
394         },
395         {       "/" OF_SOC "/serial@4500/",
396                 "clock-frequency",
397                 fdt_set_busfreq
398         },
399         {       "/" OF_SOC "/serial@4600/",
400                 "clock-frequency",
401                 fdt_set_busfreq
402         },
403 #ifdef CONFIG_MPC83XX_TSEC1
404         {       "/" OF_SOC "/ethernet@24000,
405                 "mac-address",
406                 fdt_set_eth0
407         },
408         {       "/" OF_SOC "/ethernet@24000,
409                 "local-mac-address",
410                 fdt_set_eth0
411         },
412 #endif
413 #ifdef CONFIG_MPC83XX_TSEC2
414         {       "/" OF_SOC "/ethernet@25000,
415                 "mac-address",
416                 fdt_set_eth1
417         },
418         {       "/" OF_SOC "/ethernet@25000,
419                 "local-mac-address",
420                 fdt_set_eth1
421         },
422 #endif
423 #ifdef CONFIG_UEC_ETH1
424 #if CFG_UEC1_UCC_NUM == 0  /* UCC1 */
425         {       "/" OF_QE "/ucc@2000/mac-address",
426                 "mac-address",
427                 fdt_set_eth0
428         },
429         {       "/" OF_QE "/ucc@2000/mac-address",
430                 "local-mac-address",
431                 fdt_set_eth0
432         },
433 #elif CFG_UEC1_UCC_NUM == 2  /* UCC3 */
434         {       "/" OF_QE "/ucc@2200/mac-address",
435                 "mac-address",
436                 fdt_set_eth0
437         },
438         {       "/" OF_QE "/ucc@2200/mac-address",
439                 "local-mac-address",
440                 fdt_set_eth0
441         },
442 #endif
443 #endif
444 #ifdef CONFIG_UEC_ETH2
445 #if CFG_UEC2_UCC_NUM == 1  /* UCC2 */
446         {       "/" OF_QE "/ucc@3000/mac-address",
447                 "mac-address",
448                 fdt_set_eth1
449         },
450         {       "/" OF_QE "/ucc@3000/mac-address",
451                 "local-mac-address",
452                 fdt_set_eth1
453         },
454 #elif CFG_UEC1_UCC_NUM == 3  /* UCC4 */
455         {       "/" OF_QE "/ucc@3200/mac-address",
456                 "mac-address",
457                 fdt_set_eth1
458         },
459         {       "/" OF_QE "/ucc@3200/mac-address",
460                 "local-mac-address",
461                 fdt_set_eth1
462         },
463 #endif
464 #endif
465 };
466
467 void
468 ft_cpu_setup(void *blob, bd_t *bd)
469 {
470         int  nodeoffset;
471         int  err;
472         int  j;
473
474         for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) {
475                 nodeoffset = fdt_path_offset(fdt, fixup_props[j].node);
476                 if (nodeoffset >= 0) {
477                         err = (*fixup_props[j].set_fn)(blob, nodeoffset, fixup_props[j].prop, bd);
478                         if (err < 0)
479                                 printf("set_fn/libfdt: %s %s returned %s\n",
480                                         fixup_props[j].node,
481                                         fixup_props[j].prop,
482                                         fdt_strerror(err));
483                 }
484         }
485 }
486 #endif
487
488 #if defined(CONFIG_OF_FLAT_TREE)
489 void
490 ft_cpu_setup(void *blob, bd_t *bd)
491 {
492         u32 *p;
493         int len;
494         ulong clock;
495
496         clock = bd->bi_busfreq;
497         p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len);
498         if (p != NULL)
499                 *p = cpu_to_be32(clock);
500
501         p = ft_get_prop(blob, "/" OF_SOC "/bus-frequency", &len);
502         if (p != NULL)
503                 *p = cpu_to_be32(clock);
504
505         p = ft_get_prop(blob, "/" OF_SOC "/serial@4500/clock-frequency", &len);
506         if (p != NULL)
507                 *p = cpu_to_be32(clock);
508
509         p = ft_get_prop(blob, "/" OF_SOC "/serial@4600/clock-frequency", &len);
510         if (p != NULL)
511                 *p = cpu_to_be32(clock);
512
513 #ifdef CONFIG_MPC83XX_TSEC1
514         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/mac-address", &len);
515         if (p != NULL)
516                 memcpy(p, bd->bi_enetaddr, 6);
517
518         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/local-mac-address", &len);
519         if (p != NULL)
520                 memcpy(p, bd->bi_enetaddr, 6);
521 #endif
522
523 #ifdef CONFIG_MPC83XX_TSEC2
524         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/mac-address", &len);
525         if (p != NULL)
526                 memcpy(p, bd->bi_enet1addr, 6);
527
528         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/local-mac-address", &len);
529         if (p != NULL)
530                 memcpy(p, bd->bi_enet1addr, 6);
531 #endif
532
533 #ifdef CONFIG_UEC_ETH1
534 #if CFG_UEC1_UCC_NUM == 0  /* UCC1 */
535         p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/mac-address", &len);
536         if (p != NULL)
537                 memcpy(p, bd->bi_enetaddr, 6);
538
539         p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/local-mac-address", &len);
540         if (p != NULL)
541                 memcpy(p, bd->bi_enetaddr, 6);
542 #elif CFG_UEC1_UCC_NUM == 2  /* UCC3 */
543         p = ft_get_prop(blob, "/" OF_QE "/ucc@2200/mac-address", &len);
544         if (p != NULL)
545                 memcpy(p, bd->bi_enetaddr, 6);
546
547         p = ft_get_prop(blob, "/" OF_QE "/ucc@2200/local-mac-address", &len);
548         if (p != NULL)
549                 memcpy(p, bd->bi_enetaddr, 6);
550 #endif
551 #endif
552
553 #ifdef CONFIG_UEC_ETH2
554 #if CFG_UEC2_UCC_NUM == 1  /* UCC2 */
555         p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/mac-address", &len);
556         if (p != NULL)
557                 memcpy(p, bd->bi_enet1addr, 6);
558
559         p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/local-mac-address", &len);
560         if (p != NULL)
561                 memcpy(p, bd->bi_enet1addr, 6);
562 #elif CFG_UEC2_UCC_NUM == 3  /* UCC4 */
563         p = ft_get_prop(blob, "/" OF_QE "/ucc@3200/mac-address", &len);
564         if (p != NULL)
565                 memcpy(p, bd->bi_enet1addr, 6);
566
567         p = ft_get_prop(blob, "/" OF_QE "/ucc@3200/local-mac-address", &len);
568         if (p != NULL)
569                 memcpy(p, bd->bi_enet1addr, 6);
570 #endif
571 #endif
572 }
573 #endif
574
575 #if defined(CONFIG_DDR_ECC)
576 void dma_init(void)
577 {
578         volatile immap_t *immap = (immap_t *)CFG_IMMR;
579         volatile dma83xx_t *dma = &immap->dma;
580         volatile u32 status = swab32(dma->dmasr0);
581         volatile u32 dmamr0 = swab32(dma->dmamr0);
582
583         debug("DMA-init\n");
584
585         /* initialize DMASARn, DMADAR and DMAABCRn */
586         dma->dmadar0 = (u32)0;
587         dma->dmasar0 = (u32)0;
588         dma->dmabcr0 = 0;
589
590         __asm__ __volatile__ ("sync");
591         __asm__ __volatile__ ("isync");
592
593         /* clear CS bit */
594         dmamr0 &= ~DMA_CHANNEL_START;
595         dma->dmamr0 = swab32(dmamr0);
596         __asm__ __volatile__ ("sync");
597         __asm__ __volatile__ ("isync");
598
599         /* while the channel is busy, spin */
600         while(status & DMA_CHANNEL_BUSY) {
601                 status = swab32(dma->dmasr0);
602         }
603
604         debug("DMA-init end\n");
605 }
606
607 uint dma_check(void)
608 {
609         volatile immap_t *immap = (immap_t *)CFG_IMMR;
610         volatile dma83xx_t *dma = &immap->dma;
611         volatile u32 status = swab32(dma->dmasr0);
612         volatile u32 byte_count = swab32(dma->dmabcr0);
613
614         /* while the channel is busy, spin */
615         while (status & DMA_CHANNEL_BUSY) {
616                 status = swab32(dma->dmasr0);
617         }
618
619         if (status & DMA_CHANNEL_TRANSFER_ERROR) {
620                 printf ("DMA Error: status = %x @ %d\n", status, byte_count);
621         }
622
623         return status;
624 }
625
626 int dma_xfer(void *dest, u32 count, void *src)
627 {
628         volatile immap_t *immap = (immap_t *)CFG_IMMR;
629         volatile dma83xx_t *dma = &immap->dma;
630         volatile u32 dmamr0;
631
632         /* initialize DMASARn, DMADAR and DMAABCRn */
633         dma->dmadar0 = swab32((u32)dest);
634         dma->dmasar0 = swab32((u32)src);
635         dma->dmabcr0 = swab32(count);
636
637         __asm__ __volatile__ ("sync");
638         __asm__ __volatile__ ("isync");
639
640         /* init direct transfer, clear CS bit */
641         dmamr0 = (DMA_CHANNEL_TRANSFER_MODE_DIRECT |
642                         DMA_CHANNEL_SOURCE_ADDRESS_HOLD_8B |
643                         DMA_CHANNEL_SOURCE_ADRESSS_HOLD_EN);
644
645         dma->dmamr0 = swab32(dmamr0);
646
647         __asm__ __volatile__ ("sync");
648         __asm__ __volatile__ ("isync");
649
650         /* set CS to start DMA transfer */
651         dmamr0 |= DMA_CHANNEL_START;
652         dma->dmamr0 = swab32(dmamr0);
653         __asm__ __volatile__ ("sync");
654         __asm__ __volatile__ ("isync");
655
656         return ((int)dma_check());
657 }
658 #endif /*CONFIG_DDR_ECC*/