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