3d8ca772c613933327b7ce0ae28267ba02e5e947
[pandora-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  * Change log:
23  *
24  * 20050101: Eran Liberty (liberty@freescale.com)
25  *           Initial file creating (porting from 85XX & 8260)
26  */
27
28 /*
29  * CPU specific code for the MPC83xx family.
30  *
31  * Derived from the MPC8260 and MPC85xx.
32  */
33
34 #include <common.h>
35 #include <watchdog.h>
36 #include <command.h>
37 #include <mpc83xx.h>
38 #include <ft_build.h>
39 #include <asm/processor.h>
40
41 DECLARE_GLOBAL_DATA_PTR;
42
43
44 int checkcpu(void)
45 {
46         volatile immap_t *immr;
47         ulong clock = gd->cpu_clk;
48         u32 pvr = get_pvr();
49         u32 spridr;
50         char buf[32];
51
52         immr = (immap_t *)CFG_IMMRBAR;
53
54         if ((pvr & 0xFFFF0000) != PVR_83xx) {
55                 puts("Not MPC83xx Family!!!\n");
56                 return -1;
57         }
58
59         spridr = immr->sysconf.spridr;
60         puts("CPU: ");
61         switch(spridr) {
62         case SPR_8349E_REV10:
63         case SPR_8349E_REV11:
64                 puts("MPC8349E, ");
65                 break;
66         case SPR_8349_REV10:
67         case SPR_8349_REV11:
68                 puts("MPC8349, ");
69                 break;
70         case SPR_8347E_REV10_TBGA:
71         case SPR_8347E_REV11_TBGA:
72         case SPR_8347E_REV10_PBGA:
73         case SPR_8347E_REV11_PBGA:
74                 puts("MPC8347E, ");
75                 break;
76         case SPR_8347_REV10_TBGA:
77         case SPR_8347_REV11_TBGA:
78         case SPR_8347_REV10_PBGA:
79         case SPR_8347_REV11_PBGA:
80                 puts("MPC8347, ");
81                 break;
82         case SPR_8343E_REV10:
83         case SPR_8343E_REV11:
84                 puts("MPC8343E, ");
85                 break;
86         case SPR_8343_REV10:
87         case SPR_8343_REV11:
88                 puts("MPC8343, ");
89                 break;
90         case SPR_8360E_REV10:
91         case SPR_8360E_REV11:
92         case SPR_8360E_REV12:
93                 puts("MPC8360E, ");
94                 break;
95         case SPR_8360_REV10:
96         case SPR_8360_REV11:
97         case SPR_8360_REV12:
98                 puts("MPC8360, ");
99                 break;
100         default:
101                 puts("Rev: Unknown\n");
102                 return -1;      /* Not sure what this is */
103         }
104
105 #if defined(CONFIG_MPC8349)
106         printf("Rev: %02x at %s MHz\n", (spridr & 0x0000FFFF)>>4 |(spridr & 0x0000000F), strmhz(buf, clock));
107 #else
108         printf("Rev: %02x at %s MHz\n", spridr & 0x0000FFFF, strmhz(buf, clock));
109 #endif
110         return 0;
111 }
112
113
114 /**
115  * Program a UPM with the code supplied in the table.
116  *
117  * The 'dummy' variable is used to increment the MAD. 'dummy' is
118  * supposed to be a pointer to the memory of the device being
119  * programmed by the UPM.  The data in the MDR is written into
120  * memory and the MAD is incremented every time there's a read
121  * from 'dummy'. Unfortunately, the current prototype for this
122  * function doesn't allow for passing the address of this
123  * device, and changing the prototype will break a number lots
124  * of other code, so we need to use a round-about way of finding
125  * the value for 'dummy'.
126  *
127  * The value can be extracted from the base address bits of the
128  * Base Register (BR) associated with the specific UPM.  To find
129  * that BR, we need to scan all 8 BRs until we find the one that
130  * has its MSEL bits matching the UPM we want.  Once we know the
131  * right BR, we can extract the base address bits from it.
132  *
133  * The MxMR and the BR and OR of the chosen bank should all be
134  * configured before calling this function.
135  *
136  * Parameters:
137  * upm: 0=UPMA, 1=UPMB, 2=UPMC
138  * table: Pointer to an array of values to program
139  * size: Number of elements in the array.  Must be 64 or less.
140 */
141 void upmconfig (uint upm, uint *table, uint size)
142 {
143 #if defined(CONFIG_MPC834X)
144         volatile immap_t *immap = (immap_t *) CFG_IMMRBAR;
145         volatile lbus83xx_t *lbus = &immap->lbus;
146         volatile uchar *dummy = NULL;
147         const u32 msel = (upm + 4) << BR_MSEL_SHIFT;    /* What the MSEL field in BRn should be */
148         volatile u32 *mxmr = &lbus->mamr + upm; /* Pointer to mamr, mbmr, or mcmr */
149         uint i;
150
151         /* Scan all the banks to determine the base address of the device */
152         for (i = 0; i < 8; i++) {
153                 if ((lbus->bank[i].br & BR_MSEL) == msel) {
154                         dummy = (uchar *) (lbus->bank[i].br & BR_BA);
155                         break;
156                 }
157         }
158
159         if (!dummy) {
160                 printf("Error: %s() could not find matching BR\n", __FUNCTION__);
161                 hang();
162         }
163
164         /* Set the OP field in the MxMR to "write" and the MAD field to 000000 */
165         *mxmr = (*mxmr & 0xCFFFFFC0) | 0x10000000;
166
167         for (i = 0; i < size; i++) {
168                 lbus->mdr = table[i];
169                 __asm__ __volatile__ ("sync");
170                 *dummy; /* Write the value to memory and increment MAD */
171                 __asm__ __volatile__ ("sync");
172         }
173
174         /* Set the OP field in the MxMR to "normal" and the MAD field to 000000 */
175         *mxmr &= 0xCFFFFFC0;
176 #else
177         printf("Error: %s() not defined for this configuration.\n", __FUNCTION__);
178         hang();
179 #endif
180 }
181
182
183 int
184 do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
185 {
186         ulong msr;
187 #ifndef MPC83xx_RESET
188         ulong addr;
189 #endif
190
191         volatile immap_t *immap = (immap_t *) CFG_IMMRBAR;
192
193 #ifdef MPC83xx_RESET
194         /* Interrupts and MMU off */
195         __asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
196
197         msr &= ~( MSR_EE | MSR_IR | MSR_DR);
198         __asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
199
200         /* enable Reset Control Reg */
201         immap->reset.rpr = 0x52535445;
202         __asm__ __volatile__ ("sync");
203         __asm__ __volatile__ ("isync");
204
205         /* confirm Reset Control Reg is enabled */
206         while(!((immap->reset.rcer) & RCER_CRE));
207
208         printf("Resetting the board.");
209         printf("\n");
210
211         udelay(200);
212
213         /* perform reset, only one bit */
214         immap->reset.rcr = RCR_SWHR;
215
216 #else   /* ! MPC83xx_RESET */
217
218         immap->reset.rmr = RMR_CSRE;    /* Checkstop Reset enable */
219
220         /* Interrupts and MMU off */
221         __asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
222
223         msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
224         __asm__ __volatile__ ("mtmsr    %0"::"r" (msr));
225
226         /*
227          * Trying to execute the next instruction at a non-existing address
228          * should cause a machine check, resulting in reset
229          */
230         addr = CFG_RESET_ADDRESS;
231
232         printf("resetting the board.");
233         printf("\n");
234         ((void (*)(void)) addr) ();
235 #endif  /* MPC83xx_RESET */
236
237         return 1;
238 }
239
240
241 /*
242  * Get timebase clock frequency (like cpu_clk in Hz)
243  */
244
245 unsigned long get_tbclk(void)
246 {
247         ulong tbclk;
248
249         tbclk = (gd->bus_clk + 3L) / 4L;
250
251         return tbclk;
252 }
253
254
255 #if defined(CONFIG_WATCHDOG)
256 void watchdog_reset (void)
257 {
258 #ifdef CONFIG_MPC834X
259         int re_enable = disable_interrupts();
260
261         /* Reset the 83xx watchdog */
262         volatile immap_t *immr = (immap_t *) CFG_IMMRBAR;
263         immr->wdt.swsrr = 0x556c;
264         immr->wdt.swsrr = 0xaa39;
265
266         if (re_enable)
267                 enable_interrupts ();
268 #else
269         hang();
270 #endif
271 }
272 #endif
273
274 #if defined(CONFIG_OF_FLAT_TREE)
275 void
276 ft_cpu_setup(void *blob, bd_t *bd)
277 {
278         u32 *p;
279         int len;
280         ulong clock;
281
282         clock = bd->bi_busfreq;
283         p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len);
284         if (p != NULL)
285                 *p = cpu_to_be32(clock);
286
287         p = ft_get_prop(blob, "/" OF_SOC "/bus-frequency", &len);
288         if (p != NULL)
289                 *p = cpu_to_be32(clock);
290
291         p = ft_get_prop(blob, "/" OF_SOC "/serial@4500/clock-frequency", &len);
292         if (p != NULL)
293                 *p = cpu_to_be32(clock);
294
295         p = ft_get_prop(blob, "/" OF_SOC "/serial@4600/clock-frequency", &len);
296         if (p != NULL)
297                 *p = cpu_to_be32(clock);
298
299 #ifdef CONFIG_MPC83XX_TSEC1
300         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/local-mac-address", &len);
301                 memcpy(p, bd->bi_enetaddr, 6);
302 #endif
303
304 #ifdef CONFIG_MPC83XX_TSEC2
305         p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/local-mac-address", &len);
306                 memcpy(p, bd->bi_enet1addr, 6);
307 #endif
308 }
309 #endif
310
311 #if defined(CONFIG_DDR_ECC)
312 void dma_init(void)
313 {
314         volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
315         volatile dma83xx_t *dma = &immap->dma;
316         volatile u32 status = swab32(dma->dmasr0);
317         volatile u32 dmamr0 = swab32(dma->dmamr0);
318
319         debug("DMA-init\n");
320
321         /* initialize DMASARn, DMADAR and DMAABCRn */
322         dma->dmadar0 = (u32)0;
323         dma->dmasar0 = (u32)0;
324         dma->dmabcr0 = 0;
325
326         __asm__ __volatile__ ("sync");
327         __asm__ __volatile__ ("isync");
328
329         /* clear CS bit */
330         dmamr0 &= ~DMA_CHANNEL_START;
331         dma->dmamr0 = swab32(dmamr0);
332         __asm__ __volatile__ ("sync");
333         __asm__ __volatile__ ("isync");
334
335         /* while the channel is busy, spin */
336         while(status & DMA_CHANNEL_BUSY) {
337                 status = swab32(dma->dmasr0);
338         }
339
340         debug("DMA-init end\n");
341 }
342
343 uint dma_check(void)
344 {
345         volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
346         volatile dma83xx_t *dma = &immap->dma;
347         volatile u32 status = swab32(dma->dmasr0);
348         volatile u32 byte_count = swab32(dma->dmabcr0);
349
350         /* while the channel is busy, spin */
351         while (status & DMA_CHANNEL_BUSY) {
352                 status = swab32(dma->dmasr0);
353         }
354
355         if (status & DMA_CHANNEL_TRANSFER_ERROR) {
356                 printf ("DMA Error: status = %x @ %d\n", status, byte_count);
357         }
358
359         return status;
360 }
361
362 int dma_xfer(void *dest, u32 count, void *src)
363 {
364         volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
365         volatile dma83xx_t *dma = &immap->dma;
366         volatile u32 dmamr0;
367
368         /* initialize DMASARn, DMADAR and DMAABCRn */
369         dma->dmadar0 = swab32((u32)dest);
370         dma->dmasar0 = swab32((u32)src);
371         dma->dmabcr0 = swab32(count);
372
373         __asm__ __volatile__ ("sync");
374         __asm__ __volatile__ ("isync");
375
376         /* init direct transfer, clear CS bit */
377         dmamr0 = (DMA_CHANNEL_TRANSFER_MODE_DIRECT |
378                         DMA_CHANNEL_SOURCE_ADDRESS_HOLD_8B |
379                         DMA_CHANNEL_SOURCE_ADRESSS_HOLD_EN);
380
381         dma->dmamr0 = swab32(dmamr0);
382
383         __asm__ __volatile__ ("sync");
384         __asm__ __volatile__ ("isync");
385
386         /* set CS to start DMA transfer */
387         dmamr0 |= DMA_CHANNEL_START;
388         dma->dmamr0 = swab32(dmamr0);
389         __asm__ __volatile__ ("sync");
390         __asm__ __volatile__ ("isync");
391
392         return ((int)dma_check());
393 }
394 #endif /*CONFIG_DDR_ECC*/