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