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