Add support for STX GP3SSA (stxssa) Board with 4 MiB flash.
[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         default:
128                 puts("Rev: Unknown revision number.\nWarning: Unsupported cpu revision!\n");
129                 return 0;
130         }
131
132 #if defined(CONFIG_MPC834X)
133         /* Multiple revisons of 834x processors may have the same SPRIDR value.
134          * So use PVR to identify the revision number.
135          */
136         printf("Rev: %02x at %s MHz\n", PVR_MAJ(pvr)<<4 | PVR_MIN(pvr), strmhz(buf, clock));
137 #else
138         printf("Rev: %02x at %s MHz\n", spridr & 0x0000FFFF, strmhz(buf, clock));
139 #endif
140         return 0;
141 }
142
143
144 /*
145  * Program a UPM with the code supplied in the table.
146  *
147  * The 'dummy' variable is used to increment the MAD. 'dummy' is
148  * supposed to be a pointer to the memory of the device being
149  * programmed by the UPM.  The data in the MDR is written into
150  * memory and the MAD is incremented every time there's a read
151  * from 'dummy'. Unfortunately, the current prototype for this
152  * function doesn't allow for passing the address of this
153  * device, and changing the prototype will break a number lots
154  * of other code, so we need to use a round-about way of finding
155  * the value for 'dummy'.
156  *
157  * The value can be extracted from the base address bits of the
158  * Base Register (BR) associated with the specific UPM.  To find
159  * that BR, we need to scan all 8 BRs until we find the one that
160  * has its MSEL bits matching the UPM we want.  Once we know the
161  * right BR, we can extract the base address bits from it.
162  *
163  * The MxMR and the BR and OR of the chosen bank should all be
164  * configured before calling this function.
165  *
166  * Parameters:
167  * upm: 0=UPMA, 1=UPMB, 2=UPMC
168  * table: Pointer to an array of values to program
169  * size: Number of elements in the array.  Must be 64 or less.
170  */
171 void upmconfig (uint upm, uint *table, uint size)
172 {
173 #if defined(CONFIG_MPC834X)
174         volatile immap_t *immap = (immap_t *) CFG_IMMR;
175         volatile lbus83xx_t *lbus = &immap->lbus;
176         volatile uchar *dummy = NULL;
177         const u32 msel = (upm + 4) << BR_MSEL_SHIFT;    /* What the MSEL field in BRn should be */
178         volatile u32 *mxmr = &lbus->mamr + upm; /* Pointer to mamr, mbmr, or mcmr */
179         uint i;
180
181         /* Scan all the banks to determine the base address of the device */
182         for (i = 0; i < 8; i++) {
183                 if ((lbus->bank[i].br & BR_MSEL) == msel) {
184                         dummy = (uchar *) (lbus->bank[i].br & BR_BA);
185                         break;
186                 }
187         }
188
189         if (!dummy) {
190                 printf("Error: %s() could not find matching BR\n", __FUNCTION__);
191                 hang();
192         }
193
194         /* Set the OP field in the MxMR to "write" and the MAD field to 000000 */
195         *mxmr = (*mxmr & 0xCFFFFFC0) | 0x10000000;
196
197         for (i = 0; i < size; i++) {
198                 lbus->mdr = table[i];
199                 __asm__ __volatile__ ("sync");
200                 *dummy; /* Write the value to memory and increment MAD */
201                 __asm__ __volatile__ ("sync");
202         }
203
204         /* Set the OP field in the MxMR to "normal" and the MAD field to 000000 */
205         *mxmr &= 0xCFFFFFC0;
206 #else
207         printf("Error: %s() not defined for this configuration.\n", __FUNCTION__);
208         hang();
209 #endif
210 }
211
212
213 int
214 do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
215 {
216         ulong msr;
217 #ifndef MPC83xx_RESET
218         ulong addr;
219 #endif
220
221         volatile immap_t *immap = (immap_t *) CFG_IMMR;
222
223 #ifdef MPC83xx_RESET
224         /* Interrupts and MMU off */
225         __asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
226
227         msr &= ~( MSR_EE | MSR_IR | MSR_DR);
228         __asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
229
230         /* enable Reset Control Reg */
231         immap->reset.rpr = 0x52535445;
232         __asm__ __volatile__ ("sync");
233         __asm__ __volatile__ ("isync");
234
235         /* confirm Reset Control Reg is enabled */
236         while(!((immap->reset.rcer) & RCER_CRE));
237
238         printf("Resetting the board.");
239         printf("\n");
240
241         udelay(200);
242
243         /* perform reset, only one bit */
244         immap->reset.rcr = RCR_SWHR;
245
246 #else   /* ! MPC83xx_RESET */
247
248         immap->reset.rmr = RMR_CSRE;    /* Checkstop Reset enable */
249
250         /* Interrupts and MMU off */
251         __asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
252
253         msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
254         __asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
255
256         /*
257          * Trying to execute the next instruction at a non-existing address
258          * should cause a machine check, resulting in reset
259          */
260         addr = CFG_RESET_ADDRESS;
261
262         printf("resetting the board.");
263         printf("\n");
264         ((void (*)(void)) addr) ();
265 #endif  /* MPC83xx_RESET */
266
267         return 1;
268 }
269
270
271 /*
272  * Get timebase clock frequency (like cpu_clk in Hz)
273  */
274
275 unsigned long get_tbclk(void)
276 {
277         ulong tbclk;
278
279         tbclk = (gd->bus_clk + 3L) / 4L;
280
281         return tbclk;
282 }
283
284
285 #if defined(CONFIG_WATCHDOG)
286 void watchdog_reset (void)
287 {
288         int re_enable = disable_interrupts();
289
290         /* Reset the 83xx watchdog */
291         volatile immap_t *immr = (immap_t *) CFG_IMMR;
292         immr->wdt.swsrr = 0x556c;
293         immr->wdt.swsrr = 0xaa39;
294
295         if (re_enable)
296                 enable_interrupts ();
297 }
298 #endif
299
300 #if defined(CONFIG_OF_LIBFDT)
301
302 /*
303  * "Setter" functions used to add/modify FDT entries.
304  */
305 static int fdt_set_eth0(void *fdt, int nodeoffset, const char *name, bd_t *bd)
306 {
307         /*
308          * Fix it up if it exists, don't create it if it doesn't exist.
309          */
310         if (fdt_get_property(fdt, nodeoffset, name, 0)) {
311                 return fdt_setprop(fdt, nodeoffset, name, bd->bi_enetaddr, 6);
312         }
313         return -FDT_ERR_NOTFOUND;
314 }
315 #ifdef CONFIG_HAS_ETH1
316 /* second onboard ethernet port */
317 static int fdt_set_eth1(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_enet1addr, 6);
324         }
325         return -FDT_ERR_NOTFOUND;
326 }
327 #endif
328 #ifdef CONFIG_HAS_ETH2
329 /* third onboard ethernet port */
330 static int fdt_set_eth2(void *fdt, int nodeoffset, const char *name, bd_t *bd)
331 {
332         /*
333          * Fix it up if it exists, don't create it if it doesn't exist.
334          */
335         if (fdt_get_property(fdt, nodeoffset, name, 0)) {
336                 return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet2addr, 6);
337         }
338         return -FDT_ERR_NOTFOUND;
339 }
340 #endif
341 #ifdef CONFIG_HAS_ETH3
342 /* fourth onboard ethernet port */
343 static int fdt_set_eth3(void *fdt, int nodeoffset, const char *name, bd_t *bd)
344 {
345         /*
346          * Fix it up if it exists, don't create it if it doesn't exist.
347          */
348         if (fdt_get_property(fdt, nodeoffset, name, 0)) {
349                 return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet3addr, 6);
350         }
351         return -FDT_ERR_NOTFOUND;
352 }
353 #endif
354
355 static int fdt_set_busfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd)
356 {
357         u32  tmp;
358         /*
359          * Create or update the property.
360          */
361         tmp = cpu_to_be32(bd->bi_busfreq);
362         return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
363 }
364
365 /*
366  * Fixups to the fdt.  If "create" is TRUE, the node is created
367  * unconditionally.  If "create" is FALSE, the node is updated
368  * only if it already exists.
369  */
370 static const struct {
371         char *node;
372         char *prop;
373         int (*set_fn)(void *fdt, int nodeoffset, const char *name, bd_t *bd);
374 } fixup_props[] = {
375         {       "/cpus/" OF_CPU,
376                  "bus-frequency",
377                 fdt_set_busfreq
378         },
379         {       "/cpus/" OF_SOC,
380                 "bus-frequency",
381                 fdt_set_busfreq
382         },
383         {       "/" OF_SOC "/serial@4500/",
384                 "clock-frequency",
385                 fdt_set_busfreq
386         },
387         {       "/" OF_SOC "/serial@4600/",
388                 "clock-frequency",
389                 fdt_set_busfreq
390         },
391 #ifdef CONFIG_MPC83XX_TSEC1
392         {       "/" OF_SOC "/ethernet@24000,
393                 "mac-address",
394                 fdt_set_eth0
395         },
396         {       "/" OF_SOC "/ethernet@24000,
397                 "local-mac-address",
398                 fdt_set_eth0
399         },
400 #endif
401 #ifdef CONFIG_MPC83XX_TSEC2
402         {       "/" OF_SOC "/ethernet@25000,
403                 "mac-address",
404                 fdt_set_eth1
405         },
406         {       "/" OF_SOC "/ethernet@25000,
407                 "local-mac-address",
408                 fdt_set_eth1
409         },
410 #endif
411 #ifdef CONFIG_UEC_ETH1
412 #if CFG_UEC1_UCC_NUM == 0  /* UCC1 */
413         {       "/" OF_QE "/ucc@2000/mac-address",
414                 "mac-address",
415                 fdt_set_eth0
416         },
417         {       "/" OF_QE "/ucc@2000/mac-address",
418                 "local-mac-address",
419                 fdt_set_eth0
420         },
421 #elif CFG_UEC1_UCC_NUM == 2  /* UCC3 */
422         {       "/" OF_QE "/ucc@2200/mac-address",
423                 "mac-address",
424                 fdt_set_eth0
425         },
426         {       "/" OF_QE "/ucc@2200/mac-address",
427                 "local-mac-address",
428                 fdt_set_eth0
429         },
430 #endif
431 #endif
432 #ifdef CONFIG_UEC_ETH2
433 #if CFG_UEC2_UCC_NUM == 1  /* UCC2 */
434         {       "/" OF_QE "/ucc@3000/mac-address",
435                 "mac-address",
436                 fdt_set_eth1
437         },
438         {       "/" OF_QE "/ucc@3000/mac-address",
439                 "local-mac-address",
440                 fdt_set_eth1
441         },
442 #elif CFG_UEC1_UCC_NUM == 3  /* UCC4 */
443         {       "/" OF_QE "/ucc@3200/mac-address",
444                 "mac-address",
445                 fdt_set_eth1
446         },
447         {       "/" OF_QE "/ucc@3200/mac-address",
448                 "local-mac-address",
449                 fdt_set_eth1
450         },
451 #endif
452 #endif
453 };
454
455 void
456 ft_cpu_setup(void *blob, bd_t *bd)
457 {
458         int  nodeoffset;
459         int  err;
460         int  j;
461
462         for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) {
463                 nodeoffset = fdt_path_offset(fdt, fixup_props[j].node);
464                 if (nodeoffset >= 0) {
465                         err = (*fixup_props[j].set_fn)(blob, nodeoffset, fixup_props[j].prop, bd);
466                         if (err < 0)
467                                 printf("set_fn/libfdt: %s %s returned %s\n",
468                                         fixup_props[j].node,
469                                         fixup_props[j].prop,
470                                         fdt_strerror(err));
471                 }
472         }
473 }
474 #endif
475
476 #if defined(CONFIG_OF_FLAT_TREE)
477 void
478 ft_cpu_setup(void *blob, bd_t *bd)
479 {
480         u32 *p;
481         int len;
482         ulong clock;
483
484         clock = bd->bi_busfreq;
485         p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len);
486         if (p != NULL)
487                 *p = cpu_to_be32(clock);
488
489         p = ft_get_prop(blob, "/" OF_SOC "/bus-frequency", &len);
490         if (p != NULL)
491                 *p = cpu_to_be32(clock);
492
493         p = ft_get_prop(blob, "/" OF_SOC "/serial@4500/clock-frequency", &len);
494         if (p != NULL)
495                 *p = cpu_to_be32(clock);
496
497         p = ft_get_prop(blob, "/" OF_SOC "/serial@4600/clock-frequency", &len);
498         if (p != NULL)
499                 *p = cpu_to_be32(clock);
500
501 #ifdef CONFIG_MPC83XX_TSEC1
502         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/mac-address", &len);
503         if (p != NULL)
504                 memcpy(p, bd->bi_enetaddr, 6);
505
506         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/local-mac-address", &len);
507         if (p != NULL)
508                 memcpy(p, bd->bi_enetaddr, 6);
509 #endif
510
511 #ifdef CONFIG_MPC83XX_TSEC2
512         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/mac-address", &len);
513         if (p != NULL)
514                 memcpy(p, bd->bi_enet1addr, 6);
515
516         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/local-mac-address", &len);
517         if (p != NULL)
518                 memcpy(p, bd->bi_enet1addr, 6);
519 #endif
520
521 #ifdef CONFIG_UEC_ETH1
522 #if CFG_UEC1_UCC_NUM == 0  /* UCC1 */
523         p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/mac-address", &len);
524         if (p != NULL)
525                 memcpy(p, bd->bi_enetaddr, 6);
526
527         p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/local-mac-address", &len);
528         if (p != NULL)
529                 memcpy(p, bd->bi_enetaddr, 6);
530 #elif CFG_UEC1_UCC_NUM == 2  /* UCC3 */
531         p = ft_get_prop(blob, "/" OF_QE "/ucc@2200/mac-address", &len);
532         if (p != NULL)
533                 memcpy(p, bd->bi_enetaddr, 6);
534
535         p = ft_get_prop(blob, "/" OF_QE "/ucc@2200/local-mac-address", &len);
536         if (p != NULL)
537                 memcpy(p, bd->bi_enetaddr, 6);
538 #endif
539 #endif
540
541 #ifdef CONFIG_UEC_ETH2
542 #if CFG_UEC2_UCC_NUM == 1  /* UCC2 */
543         p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/mac-address", &len);
544         if (p != NULL)
545                 memcpy(p, bd->bi_enet1addr, 6);
546
547         p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/local-mac-address", &len);
548         if (p != NULL)
549                 memcpy(p, bd->bi_enet1addr, 6);
550 #elif CFG_UEC2_UCC_NUM == 3  /* UCC4 */
551         p = ft_get_prop(blob, "/" OF_QE "/ucc@3200/mac-address", &len);
552         if (p != NULL)
553                 memcpy(p, bd->bi_enet1addr, 6);
554
555         p = ft_get_prop(blob, "/" OF_QE "/ucc@3200/local-mac-address", &len);
556         if (p != NULL)
557                 memcpy(p, bd->bi_enet1addr, 6);
558 #endif
559 #endif
560 }
561 #endif
562
563 #if defined(CONFIG_DDR_ECC)
564 void dma_init(void)
565 {
566         volatile immap_t *immap = (immap_t *)CFG_IMMR;
567         volatile dma83xx_t *dma = &immap->dma;
568         volatile u32 status = swab32(dma->dmasr0);
569         volatile u32 dmamr0 = swab32(dma->dmamr0);
570
571         debug("DMA-init\n");
572
573         /* initialize DMASARn, DMADAR and DMAABCRn */
574         dma->dmadar0 = (u32)0;
575         dma->dmasar0 = (u32)0;
576         dma->dmabcr0 = 0;
577
578         __asm__ __volatile__ ("sync");
579         __asm__ __volatile__ ("isync");
580
581         /* clear CS bit */
582         dmamr0 &= ~DMA_CHANNEL_START;
583         dma->dmamr0 = swab32(dmamr0);
584         __asm__ __volatile__ ("sync");
585         __asm__ __volatile__ ("isync");
586
587         /* while the channel is busy, spin */
588         while(status & DMA_CHANNEL_BUSY) {
589                 status = swab32(dma->dmasr0);
590         }
591
592         debug("DMA-init end\n");
593 }
594
595 uint dma_check(void)
596 {
597         volatile immap_t *immap = (immap_t *)CFG_IMMR;
598         volatile dma83xx_t *dma = &immap->dma;
599         volatile u32 status = swab32(dma->dmasr0);
600         volatile u32 byte_count = swab32(dma->dmabcr0);
601
602         /* while the channel is busy, spin */
603         while (status & DMA_CHANNEL_BUSY) {
604                 status = swab32(dma->dmasr0);
605         }
606
607         if (status & DMA_CHANNEL_TRANSFER_ERROR) {
608                 printf ("DMA Error: status = %x @ %d\n", status, byte_count);
609         }
610
611         return status;
612 }
613
614 int dma_xfer(void *dest, u32 count, void *src)
615 {
616         volatile immap_t *immap = (immap_t *)CFG_IMMR;
617         volatile dma83xx_t *dma = &immap->dma;
618         volatile u32 dmamr0;
619
620         /* initialize DMASARn, DMADAR and DMAABCRn */
621         dma->dmadar0 = swab32((u32)dest);
622         dma->dmasar0 = swab32((u32)src);
623         dma->dmabcr0 = swab32(count);
624
625         __asm__ __volatile__ ("sync");
626         __asm__ __volatile__ ("isync");
627
628         /* init direct transfer, clear CS bit */
629         dmamr0 = (DMA_CHANNEL_TRANSFER_MODE_DIRECT |
630                         DMA_CHANNEL_SOURCE_ADDRESS_HOLD_8B |
631                         DMA_CHANNEL_SOURCE_ADRESSS_HOLD_EN);
632
633         dma->dmamr0 = swab32(dmamr0);
634
635         __asm__ __volatile__ ("sync");
636         __asm__ __volatile__ ("isync");
637
638         /* set CS to start DMA transfer */
639         dmamr0 |= DMA_CHANNEL_START;
640         dma->dmamr0 = swab32(dmamr0);
641         __asm__ __volatile__ ("sync");
642         __asm__ __volatile__ ("isync");
643
644         return ((int)dma_check());
645 }
646 #endif /*CONFIG_DDR_ECC*/