blob: aa4d9b1f1b373ba8b6d33f939f1325906acc540c [file] [log] [blame]
Eran Liberty9095d4a2005-07-28 10:08:46 -05001/*
Dave Liuf5035922006-10-25 14:41:21 -05002 * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
Eran Liberty9095d4a2005-07-28 10:08:46 -05003 *
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
Eran Liberty9095d4a2005-07-28 10:08:46 -050021 */
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>
Gerald Van Barend6abef42007-03-31 12:23:51 -040034#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
Eran Liberty9095d4a2005-07-28 10:08:46 -050041
Wolfgang Denk6405a152006-03-31 18:32:53 +020042DECLARE_GLOBAL_DATA_PTR;
43
Eran Liberty9095d4a2005-07-28 10:08:46 -050044
45int checkcpu(void)
46{
Dave Liua46daea2006-11-03 19:33:44 -060047 volatile immap_t *immr;
Eran Liberty9095d4a2005-07-28 10:08:46 -050048 ulong clock = gd->cpu_clk;
49 u32 pvr = get_pvr();
Dave Liua46daea2006-11-03 19:33:44 -060050 u32 spridr;
Eran Liberty9095d4a2005-07-28 10:08:46 -050051 char buf[32];
52
Timur Tabi386a2802006-11-03 12:00:28 -060053 immr = (immap_t *)CFG_IMMR;
Dave Liua46daea2006-11-03 19:33:44 -060054
Eran Liberty9095d4a2005-07-28 10:08:46 -050055 if ((pvr & 0xFFFF0000) != PVR_83xx) {
56 puts("Not MPC83xx Family!!!\n");
57 return -1;
58 }
59
Dave Liua46daea2006-11-03 19:33:44 -060060 spridr = immr->sysconf.spridr;
61 puts("CPU: ");
62 switch(spridr) {
63 case SPR_8349E_REV10:
64 case SPR_8349E_REV11:
Xie Xiaobo800b7532007-02-14 18:26:44 +080065 case SPR_8349E_REV31:
Dave Liua46daea2006-11-03 19:33:44 -060066 puts("MPC8349E, ");
67 break;
68 case SPR_8349_REV10:
69 case SPR_8349_REV11:
Xie Xiaobo800b7532007-02-14 18:26:44 +080070 case SPR_8349_REV31:
Dave Liua46daea2006-11-03 19:33:44 -060071 puts("MPC8349, ");
72 break;
73 case SPR_8347E_REV10_TBGA:
74 case SPR_8347E_REV11_TBGA:
Xie Xiaobo800b7532007-02-14 18:26:44 +080075 case SPR_8347E_REV31_TBGA:
Dave Liua46daea2006-11-03 19:33:44 -060076 case SPR_8347E_REV10_PBGA:
77 case SPR_8347E_REV11_PBGA:
Xie Xiaobo800b7532007-02-14 18:26:44 +080078 case SPR_8347E_REV31_PBGA:
Dave Liua46daea2006-11-03 19:33:44 -060079 puts("MPC8347E, ");
80 break;
81 case SPR_8347_REV10_TBGA:
82 case SPR_8347_REV11_TBGA:
Xie Xiaobo800b7532007-02-14 18:26:44 +080083 case SPR_8347_REV31_TBGA:
Dave Liua46daea2006-11-03 19:33:44 -060084 case SPR_8347_REV10_PBGA:
85 case SPR_8347_REV11_PBGA:
Xie Xiaobo800b7532007-02-14 18:26:44 +080086 case SPR_8347_REV31_PBGA:
Dave Liua46daea2006-11-03 19:33:44 -060087 puts("MPC8347, ");
Eran Liberty9095d4a2005-07-28 10:08:46 -050088 break;
Dave Liua46daea2006-11-03 19:33:44 -060089 case SPR_8343E_REV10:
90 case SPR_8343E_REV11:
Xie Xiaobo800b7532007-02-14 18:26:44 +080091 case SPR_8343E_REV31:
Dave Liua46daea2006-11-03 19:33:44 -060092 puts("MPC8343E, ");
93 break;
94 case SPR_8343_REV10:
95 case SPR_8343_REV11:
Xie Xiaobo800b7532007-02-14 18:26:44 +080096 case SPR_8343_REV31:
Dave Liua46daea2006-11-03 19:33:44 -060097 puts("MPC8343, ");
98 break;
99 case SPR_8360E_REV10:
100 case SPR_8360E_REV11:
101 case SPR_8360E_REV12:
Xie Xiaoboa9be42a2007-02-14 18:27:06 +0800102 case SPR_8360E_REV20:
Dave Liua46daea2006-11-03 19:33:44 -0600103 puts("MPC8360E, ");
104 break;
105 case SPR_8360_REV10:
106 case SPR_8360_REV11:
107 case SPR_8360_REV12:
Xie Xiaoboa9be42a2007-02-14 18:27:06 +0800108 case SPR_8360_REV20:
Dave Liua46daea2006-11-03 19:33:44 -0600109 puts("MPC8360, ");
Eran Liberty9095d4a2005-07-28 10:08:46 -0500110 break;
Dave Liue740c462006-12-07 21:13:15 +0800111 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;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500127 default:
Xie Xiaobo800b7532007-02-14 18:26:44 +0800128 puts("Rev: Unknown revision number.\nWarning: Unsupported cpu revision!\n");
129 return 0;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500130 }
Rafal Jaworowski384da5e2005-10-17 02:39:53 +0200131
Kumar Galab7870e72007-01-30 14:08:30 -0600132#if defined(CONFIG_MPC834X)
Xie Xiaobo800b7532007-02-14 18:26:44 +0800133 /* 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));
Dave Liua46daea2006-11-03 19:33:44 -0600137#else
138 printf("Rev: %02x at %s MHz\n", spridr & 0x0000FFFF, strmhz(buf, clock));
139#endif
Eran Liberty9095d4a2005-07-28 10:08:46 -0500140 return 0;
141}
142
143
Timur Tabiab347542006-11-03 19:15:00 -0600144/*
Timur Tabi054838e2006-10-31 18:44:42 -0600145 * 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.
Timur Tabiab347542006-11-03 19:15:00 -0600170 */
Eran Liberty9095d4a2005-07-28 10:08:46 -0500171void upmconfig (uint upm, uint *table, uint size)
172{
Timur Tabi054838e2006-10-31 18:44:42 -0600173#if defined(CONFIG_MPC834X)
Timur Tabi386a2802006-11-03 12:00:28 -0600174 volatile immap_t *immap = (immap_t *) CFG_IMMR;
Timur Tabi054838e2006-10-31 18:44:42 -0600175 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
Eran Liberty9095d4a2005-07-28 10:08:46 -0500210}
211
212
213int
214do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
215{
Wolfgang Denk301d0962005-08-05 19:49:35 +0200216 ulong msr;
217#ifndef MPC83xx_RESET
218 ulong addr;
219#endif
Eran Liberty9095d4a2005-07-28 10:08:46 -0500220
Timur Tabi386a2802006-11-03 12:00:28 -0600221 volatile immap_t *immap = (immap_t *) CFG_IMMR;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500222
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;
Marian Balakowicz919b1872006-03-14 16:12:48 +0100232 __asm__ __volatile__ ("sync");
233 __asm__ __volatile__ ("isync");
Eran Liberty9095d4a2005-07-28 10:08:46 -0500234
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 */
Wolfgang Denk301d0962005-08-05 19:49:35 +0200244 immap->reset.rcr = RCR_SWHR;
245
246#else /* ! MPC83xx_RESET */
Eran Liberty9095d4a2005-07-28 10:08:46 -0500247
Wolfgang Denk301d0962005-08-05 19:49:35 +0200248 immap->reset.rmr = RMR_CSRE; /* Checkstop Reset enable */
249
250 /* Interrupts and MMU off */
251 __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
Eran Liberty9095d4a2005-07-28 10:08:46 -0500252
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) ();
Wolfgang Denk301d0962005-08-05 19:49:35 +0200265#endif /* MPC83xx_RESET */
266
Eran Liberty9095d4a2005-07-28 10:08:46 -0500267 return 1;
268}
269
270
271/*
272 * Get timebase clock frequency (like cpu_clk in Hz)
273 */
274
275unsigned long get_tbclk(void)
276{
Eran Liberty9095d4a2005-07-28 10:08:46 -0500277 ulong tbclk;
278
279 tbclk = (gd->bus_clk + 3L) / 4L;
280
281 return tbclk;
282}
283
284
285#if defined(CONFIG_WATCHDOG)
286void watchdog_reset (void)
287{
Timur Tabi054838e2006-10-31 18:44:42 -0600288 int re_enable = disable_interrupts();
289
290 /* Reset the 83xx watchdog */
Timur Tabi386a2802006-11-03 12:00:28 -0600291 volatile immap_t *immr = (immap_t *) CFG_IMMR;
Timur Tabi054838e2006-10-31 18:44:42 -0600292 immr->wdt.swsrr = 0x556c;
293 immr->wdt.swsrr = 0xaa39;
294
295 if (re_enable)
296 enable_interrupts ();
Eran Liberty9095d4a2005-07-28 10:08:46 -0500297}
Timur Tabi054838e2006-10-31 18:44:42 -0600298#endif
Kumar Gala5bbb0452006-01-11 16:48:10 -0600299
Gerald Van Barend6abef42007-03-31 12:23:51 -0400300#if defined(CONFIG_OF_LIBFDT)
301
302/*
303 * Fixups to the fdt. If "create" is TRUE, the node is created
304 * unconditionally. If "create" is FALSE, the node is updated
305 * only if it already exists.
306 */
307#define FT_UPDATE 0x00000000 /* update existing property only */
308#define FT_CREATE 0x00000001 /* create property if it doesn't exist */
309#define FT_BUSFREQ 0x00000002 /* source is bd->bi_busfreq */
310#define FT_ENETADDR 0x00000004 /* source is bd->bi_enetaddr */
311static const struct {
312 int createflags;
313 char *node;
314 char *prop;
315} fixup_props[] = {
316 { FT_CREATE | FT_BUSFREQ,
317 "/cpus/" OF_CPU,
318 "bus-frequency",
319 },
320 { FT_CREATE | FT_BUSFREQ,
321 "/cpus/" OF_SOC,
322 "bus-frequency"
323 },
324 { FT_CREATE | FT_BUSFREQ,
325 "/" OF_SOC "/serial@4500/",
326 "clock-frequency"
327 },
328 { FT_CREATE | FT_BUSFREQ,
329 "/" OF_SOC "/serial@4600/",
330 "clock-frequency"
331 },
332#ifdef CONFIG_MPC83XX_TSEC1
333 { FT_UPDATE | FT_ENETADDR,
334 "/" OF_SOC "/ethernet@24000,
335 "mac-address",
336 },
337 { FT_UPDATE | FT_ENETADDR,
338 "/" OF_SOC "/ethernet@24000,
339 "local-mac-address",
340 },
341#endif
342#ifdef CONFIG_MPC83XX_TSEC2
343 { FT_UPDATE | FT_ENETADDR,
344 "/" OF_SOC "/ethernet@25000,
345 "mac-address",
346 },
347 { FT_UPDATE | FT_ENETADDR,
348 "/" OF_SOC "/ethernet@25000,
349 "local-mac-address",
350 },
351#endif
352};
353
354void
355ft_cpu_setup(void *blob, bd_t *bd)
356{
357 int nodeoffset;
358 int err;
359 int j;
360
361 for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) {
362 nodeoffset = fdt_path_offset (fdt, fixup_props[j].node);
363 if (nodeoffset >= 0) {
364 /*
365 * If unconditional create or the property already exists...
366 */
Gerald Van Barenc4a57ea2007-04-06 14:19:43 -0400367 err = 0;
Gerald Van Barend6abef42007-03-31 12:23:51 -0400368 if ((fixup_props[j].createflags & FT_CREATE) ||
369 (fdt_get_property(fdt, nodeoffset, fixup_props[j].prop, 0))) {
370 if (fixup_props[j].createflags & FT_BUSFREQ) {
371 u32 tmp;
372
373 tmp = cpu_to_be32(bd->bi_busfreq);
374 err = fdt_setprop(fdt, nodeoffset,
375 fixup_props[j].prop, &tmp, sizeof(tmp));
376 } else if (fixup_props[j].createflags & FT_ENETADDR) {
377 err = fdt_setprop(fdt, nodeoffset,
378 fixup_props[j].prop, bd->bi_enetaddr, 6);
379 } else {
380 printf("ft_cpu_setup: %s %s has no flag for the value to set\n",
Gerald Van Baren32480892007-03-31 14:30:53 -0400381 fixup_props[j].node,
Gerald Van Barend6abef42007-03-31 12:23:51 -0400382 fixup_props[j].prop);
383 }
384 if (err < 0)
385 printf("libfdt: %s %s returned %s\n",
Gerald Van Baren32480892007-03-31 14:30:53 -0400386 fixup_props[j].node,
Gerald Van Barend6abef42007-03-31 12:23:51 -0400387 fixup_props[j].prop,
388 fdt_strerror(err));
389 }
390 }
391 }
392}
393#endif
394
Kumar Gala5bbb0452006-01-11 16:48:10 -0600395#if defined(CONFIG_OF_FLAT_TREE)
396void
397ft_cpu_setup(void *blob, bd_t *bd)
398{
399 u32 *p;
400 int len;
401 ulong clock;
402
403 clock = bd->bi_busfreq;
404 p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len);
405 if (p != NULL)
406 *p = cpu_to_be32(clock);
407
408 p = ft_get_prop(blob, "/" OF_SOC "/bus-frequency", &len);
409 if (p != NULL)
410 *p = cpu_to_be32(clock);
411
412 p = ft_get_prop(blob, "/" OF_SOC "/serial@4500/clock-frequency", &len);
413 if (p != NULL)
414 *p = cpu_to_be32(clock);
415
416 p = ft_get_prop(blob, "/" OF_SOC "/serial@4600/clock-frequency", &len);
417 if (p != NULL)
418 *p = cpu_to_be32(clock);
419
420#ifdef CONFIG_MPC83XX_TSEC1
Timur Tabief648382007-02-13 10:41:42 -0600421 p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/mac-address", &len);
422 if (p != NULL)
423 memcpy(p, bd->bi_enetaddr, 6);
424
Kim Phillipsd99bd8b2006-11-01 00:07:25 -0600425 p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/local-mac-address", &len);
Kim Phillips24f63e92007-01-30 16:15:21 -0600426 if (p != NULL)
Kumar Gala5bbb0452006-01-11 16:48:10 -0600427 memcpy(p, bd->bi_enetaddr, 6);
428#endif
429
430#ifdef CONFIG_MPC83XX_TSEC2
Timur Tabief648382007-02-13 10:41:42 -0600431 p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/mac-address", &len);
432 if (p != NULL)
433 memcpy(p, bd->bi_enet1addr, 6);
434
Kim Phillipsd99bd8b2006-11-01 00:07:25 -0600435 p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/local-mac-address", &len);
Kim Phillips24f63e92007-01-30 16:15:21 -0600436 if (p != NULL)
Kumar Gala5bbb0452006-01-11 16:48:10 -0600437 memcpy(p, bd->bi_enet1addr, 6);
438#endif
Kim Phillips526addb2007-02-22 20:06:57 -0600439
440#ifdef CONFIG_UEC_ETH1
441#if CFG_UEC1_UCC_NUM == 0 /* UCC1 */
442 p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/mac-address", &len);
443 if (p != NULL)
444 memcpy(p, bd->bi_enetaddr, 6);
445
446 p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/local-mac-address", &len);
447 if (p != NULL)
448 memcpy(p, bd->bi_enetaddr, 6);
449#elif CFG_UEC1_UCC_NUM == 2 /* UCC3 */
450 p = ft_get_prop(blob, "/" OF_QE "/ucc@2200/mac-address", &len);
451 if (p != NULL)
452 memcpy(p, bd->bi_enetaddr, 6);
453
454 p = ft_get_prop(blob, "/" OF_QE "/ucc@2200/local-mac-address", &len);
455 if (p != NULL)
456 memcpy(p, bd->bi_enetaddr, 6);
457#endif
458#endif
459
460#ifdef CONFIG_UEC_ETH2
461#if CFG_UEC2_UCC_NUM == 1 /* UCC2 */
462 p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/mac-address", &len);
463 if (p != NULL)
464 memcpy(p, bd->bi_enet1addr, 6);
465
466 p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/local-mac-address", &len);
467 if (p != NULL)
468 memcpy(p, bd->bi_enet1addr, 6);
469#elif CFG_UEC2_UCC_NUM == 3 /* UCC4 */
470 p = ft_get_prop(blob, "/" OF_QE "/ucc@3200/mac-address", &len);
471 if (p != NULL)
472 memcpy(p, bd->bi_enet1addr, 6);
473
474 p = ft_get_prop(blob, "/" OF_QE "/ucc@3200/local-mac-address", &len);
475 if (p != NULL)
476 memcpy(p, bd->bi_enet1addr, 6);
477#endif
478#endif
Kumar Gala5bbb0452006-01-11 16:48:10 -0600479}
480#endif
Marian Balakowicz7ec9ebc2006-03-14 16:14:48 +0100481
482#if defined(CONFIG_DDR_ECC)
483void dma_init(void)
484{
Timur Tabi386a2802006-11-03 12:00:28 -0600485 volatile immap_t *immap = (immap_t *)CFG_IMMR;
Dave Liuf5035922006-10-25 14:41:21 -0500486 volatile dma83xx_t *dma = &immap->dma;
Marian Balakowicz7ec9ebc2006-03-14 16:14:48 +0100487 volatile u32 status = swab32(dma->dmasr0);
488 volatile u32 dmamr0 = swab32(dma->dmamr0);
489
490 debug("DMA-init\n");
491
492 /* initialize DMASARn, DMADAR and DMAABCRn */
493 dma->dmadar0 = (u32)0;
494 dma->dmasar0 = (u32)0;
495 dma->dmabcr0 = 0;
496
497 __asm__ __volatile__ ("sync");
498 __asm__ __volatile__ ("isync");
499
500 /* clear CS bit */
501 dmamr0 &= ~DMA_CHANNEL_START;
502 dma->dmamr0 = swab32(dmamr0);
503 __asm__ __volatile__ ("sync");
504 __asm__ __volatile__ ("isync");
505
506 /* while the channel is busy, spin */
507 while(status & DMA_CHANNEL_BUSY) {
508 status = swab32(dma->dmasr0);
509 }
510
511 debug("DMA-init end\n");
512}
513
514uint dma_check(void)
515{
Timur Tabi386a2802006-11-03 12:00:28 -0600516 volatile immap_t *immap = (immap_t *)CFG_IMMR;
Dave Liuf5035922006-10-25 14:41:21 -0500517 volatile dma83xx_t *dma = &immap->dma;
Marian Balakowicz7ec9ebc2006-03-14 16:14:48 +0100518 volatile u32 status = swab32(dma->dmasr0);
519 volatile u32 byte_count = swab32(dma->dmabcr0);
520
521 /* while the channel is busy, spin */
522 while (status & DMA_CHANNEL_BUSY) {
523 status = swab32(dma->dmasr0);
524 }
525
526 if (status & DMA_CHANNEL_TRANSFER_ERROR) {
527 printf ("DMA Error: status = %x @ %d\n", status, byte_count);
528 }
529
530 return status;
531}
532
533int dma_xfer(void *dest, u32 count, void *src)
534{
Timur Tabi386a2802006-11-03 12:00:28 -0600535 volatile immap_t *immap = (immap_t *)CFG_IMMR;
Dave Liuf5035922006-10-25 14:41:21 -0500536 volatile dma83xx_t *dma = &immap->dma;
Marian Balakowicz7ec9ebc2006-03-14 16:14:48 +0100537 volatile u32 dmamr0;
538
539 /* initialize DMASARn, DMADAR and DMAABCRn */
540 dma->dmadar0 = swab32((u32)dest);
541 dma->dmasar0 = swab32((u32)src);
542 dma->dmabcr0 = swab32(count);
543
544 __asm__ __volatile__ ("sync");
545 __asm__ __volatile__ ("isync");
546
547 /* init direct transfer, clear CS bit */
548 dmamr0 = (DMA_CHANNEL_TRANSFER_MODE_DIRECT |
549 DMA_CHANNEL_SOURCE_ADDRESS_HOLD_8B |
550 DMA_CHANNEL_SOURCE_ADRESSS_HOLD_EN);
Wolfgang Denkebd3deb2006-04-16 10:51:58 +0200551
Marian Balakowicz7ec9ebc2006-03-14 16:14:48 +0100552 dma->dmamr0 = swab32(dmamr0);
553
554 __asm__ __volatile__ ("sync");
555 __asm__ __volatile__ ("isync");
556
557 /* set CS to start DMA transfer */
558 dmamr0 |= DMA_CHANNEL_START;
559 dma->dmamr0 = swab32(dmamr0);
560 __asm__ __volatile__ ("sync");
561 __asm__ __volatile__ ("isync");
562
563 return ((int)dma_check());
564}
565#endif /*CONFIG_DDR_ECC*/