]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/powerpc/boot/4xx.c
1a83efe274c12023bceed06bb6491d00d1710fad
[linux-2.6-omap-h63xx.git] / arch / powerpc / boot / 4xx.c
1 /*
2  * Copyright 2007 David Gibson, IBM Corporation.
3  *
4  * Based on earlier code:
5  *   Matt Porter <mporter@kernel.crashing.org>
6  *   Copyright 2002-2005 MontaVista Software Inc.
7  *
8  *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
9  *   Copyright (c) 2003, 2004 Zultys Technologies
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version
14  * 2 of the License, or (at your option) any later version.
15  */
16 #include <stddef.h>
17 #include "types.h"
18 #include "string.h"
19 #include "stdio.h"
20 #include "ops.h"
21 #include "reg.h"
22 #include "dcr.h"
23
24 /* Read the 4xx SDRAM controller to get size of system memory. */
25 void ibm4xx_sdram_fixup_memsize(void)
26 {
27         int i;
28         unsigned long memsize, bank_config;
29
30         memsize = 0;
31         for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) {
32                 bank_config = SDRAM0_READ(sdram_bxcr[i]);
33                 if (bank_config & SDRAM_CONFIG_BANK_ENABLE)
34                         memsize += SDRAM_CONFIG_BANK_SIZE(bank_config);
35         }
36
37         dt_fixup_memory(0, memsize);
38 }
39
40 /* Read the 440SPe MQ controller to get size of system memory. */
41 #define DCRN_MQ0_B0BAS          0x40
42 #define DCRN_MQ0_B1BAS          0x41
43 #define DCRN_MQ0_B2BAS          0x42
44 #define DCRN_MQ0_B3BAS          0x43
45
46 static u64 ibm440spe_decode_bas(u32 bas)
47 {
48         u64 base = ((u64)(bas & 0xFFE00000u)) << 2;
49
50         /* open coded because I'm paranoid about invalid values */
51         switch ((bas >> 4) & 0xFFF) {
52         case 0:
53                 return 0;
54         case 0xffc:
55                 return base + 0x000800000ull;
56         case 0xff8:
57                 return base + 0x001000000ull;
58         case 0xff0:
59                 return base + 0x002000000ull;
60         case 0xfe0:
61                 return base + 0x004000000ull;
62         case 0xfc0:
63                 return base + 0x008000000ull;
64         case 0xf80:
65                 return base + 0x010000000ull;
66         case 0xf00:
67                 return base + 0x020000000ull;
68         case 0xe00:
69                 return base + 0x040000000ull;
70         case 0xc00:
71                 return base + 0x080000000ull;
72         case 0x800:
73                 return base + 0x100000000ull;
74         }
75         printf("Memory BAS value 0x%08x unsupported !\n", bas);
76         return 0;
77 }
78
79 void ibm440spe_fixup_memsize(void)
80 {
81         u64 banktop, memsize = 0;
82
83         /* Ultimately, we should directly construct the memory node
84          * so we are able to handle holes in the memory address space
85          */
86         banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B0BAS));
87         if (banktop > memsize)
88                 memsize = banktop;
89         banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B1BAS));
90         if (banktop > memsize)
91                 memsize = banktop;
92         banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B2BAS));
93         if (banktop > memsize)
94                 memsize = banktop;
95         banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B3BAS));
96         if (banktop > memsize)
97                 memsize = banktop;
98
99         dt_fixup_memory(0, memsize);
100 }
101
102
103 /* 4xx DDR1/2 Denali memory controller support */
104 /* DDR0 registers */
105 #define DDR0_02                 2
106 #define DDR0_08                 8
107 #define DDR0_10                 10
108 #define DDR0_14                 14
109 #define DDR0_42                 42
110 #define DDR0_43                 43
111
112 /* DDR0_02 */
113 #define DDR_START               0x1
114 #define DDR_START_SHIFT         0
115 #define DDR_MAX_CS_REG          0x3
116 #define DDR_MAX_CS_REG_SHIFT    24
117 #define DDR_MAX_COL_REG         0xf
118 #define DDR_MAX_COL_REG_SHIFT   16
119 #define DDR_MAX_ROW_REG         0xf
120 #define DDR_MAX_ROW_REG_SHIFT   8
121 /* DDR0_08 */
122 #define DDR_DDR2_MODE           0x1
123 #define DDR_DDR2_MODE_SHIFT     0
124 /* DDR0_10 */
125 #define DDR_CS_MAP              0x3
126 #define DDR_CS_MAP_SHIFT        8
127 /* DDR0_14 */
128 #define DDR_REDUC               0x1
129 #define DDR_REDUC_SHIFT         16
130 /* DDR0_42 */
131 #define DDR_APIN                0x7
132 #define DDR_APIN_SHIFT          24
133 /* DDR0_43 */
134 #define DDR_COL_SZ              0x7
135 #define DDR_COL_SZ_SHIFT        8
136 #define DDR_BANK8               0x1
137 #define DDR_BANK8_SHIFT         0
138
139 #define DDR_GET_VAL(val, mask, shift)   (((val) >> (shift)) & (mask))
140
141 void ibm4xx_denali_fixup_memsize(void)
142 {
143         u32 val, max_cs, max_col, max_row;
144         u32 cs, col, row, bank, dpath;
145         unsigned long memsize;
146
147         val = SDRAM0_READ(DDR0_02);
148         if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT))
149                 fatal("DDR controller is not initialized\n");
150
151         /* get maximum cs col and row values */
152         max_cs  = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT);
153         max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT);
154         max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT);
155
156         /* get CS value */
157         val = SDRAM0_READ(DDR0_10);
158
159         val = DDR_GET_VAL(val, DDR_CS_MAP, DDR_CS_MAP_SHIFT);
160         cs = 0;
161         while (val) {
162                 if (val && 0x1)
163                         cs++;
164                 val = val >> 1;
165         }
166
167         if (!cs)
168                 fatal("No memory installed\n");
169         if (cs > max_cs)
170                 fatal("DDR wrong CS configuration\n");
171
172         /* get data path bytes */
173         val = SDRAM0_READ(DDR0_14);
174
175         if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT))
176                 dpath = 8; /* 64 bits */
177         else
178                 dpath = 4; /* 32 bits */
179
180         /* get address pins (rows) */
181         val = SDRAM0_READ(DDR0_42);
182
183         row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT);
184         if (row > max_row)
185                 fatal("DDR wrong APIN configuration\n");
186         row = max_row - row;
187
188         /* get collomn size and banks */
189         val = SDRAM0_READ(DDR0_43);
190
191         col = DDR_GET_VAL(val, DDR_COL_SZ, DDR_COL_SZ_SHIFT);
192         if (col > max_col)
193                 fatal("DDR wrong COL configuration\n");
194         col = max_col - col;
195
196         if (DDR_GET_VAL(val, DDR_BANK8, DDR_BANK8_SHIFT))
197                 bank = 8; /* 8 banks */
198         else
199                 bank = 4; /* 4 banks */
200
201         memsize = cs * (1 << (col+row)) * bank * dpath;
202         dt_fixup_memory(0, memsize);
203 }
204
205 #define SPRN_DBCR0_40X 0x3F2
206 #define SPRN_DBCR0_44X 0x134
207 #define DBCR0_RST_SYSTEM 0x30000000
208
209 void ibm44x_dbcr_reset(void)
210 {
211         unsigned long tmp;
212
213         asm volatile (
214                 "mfspr  %0,%1\n"
215                 "oris   %0,%0,%2@h\n"
216                 "mtspr  %1,%0"
217                 : "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM)
218                 );
219
220 }
221
222 void ibm40x_dbcr_reset(void)
223 {
224         unsigned long tmp;
225
226         asm volatile (
227                 "mfspr  %0,%1\n"
228                 "oris   %0,%0,%2@h\n"
229                 "mtspr  %1,%0"
230                 : "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM)
231                 );
232 }
233
234 #define EMAC_RESET 0x20000000
235 void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1)
236 {
237         /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
238          * do this for us
239          */
240         if (emac0)
241                 *emac0 = EMAC_RESET;
242         if (emac1)
243                 *emac1 = EMAC_RESET;
244
245         mtdcr(DCRN_MAL0_CFG, MAL_RESET);
246         while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET) {};
247 }
248
249 /* Read 4xx EBC bus bridge registers to get mappings of the peripheral
250  * banks into the OPB address space */
251 void ibm4xx_fixup_ebc_ranges(const char *ebc)
252 {
253         void *devp;
254         u32 bxcr;
255         u32 ranges[EBC_NUM_BANKS*4];
256         u32 *p = ranges;
257         int i;
258
259         for (i = 0; i < EBC_NUM_BANKS; i++) {
260                 mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i));
261                 bxcr = mfdcr(DCRN_EBC0_CFGDATA);
262
263                 if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) {
264                         *p++ = i;
265                         *p++ = 0;
266                         *p++ = bxcr & EBC_BXCR_BAS;
267                         *p++ = EBC_BXCR_BANK_SIZE(bxcr);
268                 }
269         }
270
271         devp = finddevice(ebc);
272         if (! devp)
273                 fatal("Couldn't locate EBC node %s\n\r", ebc);
274
275         setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32));
276 }
277
278 /* Calculate 440GP clocks */
279 void ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
280 {
281         u32 sys0 = mfdcr(DCRN_CPC0_SYS0);
282         u32 cr0 = mfdcr(DCRN_CPC0_CR0);
283         u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
284         u32 opdv = CPC0_SYS0_OPDV(sys0);
285         u32 epdv = CPC0_SYS0_EPDV(sys0);
286
287         if (sys0 & CPC0_SYS0_BYPASS) {
288                 /* Bypass system PLL */
289                 cpu = plb = sys_clk;
290         } else {
291                 if (sys0 & CPC0_SYS0_EXTSL)
292                         /* PerClk */
293                         m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv;
294                 else
295                         /* CPU clock */
296                         m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0);
297                 cpu = sys_clk * m / CPC0_SYS0_FWDVA(sys0);
298                 plb = sys_clk * m / CPC0_SYS0_FWDVB(sys0);
299         }
300
301         opb = plb / opdv;
302         ebc = opb / epdv;
303
304         /* FIXME: Check if this is for all 440GP, or just Ebony */
305         if ((mfpvr() & 0xf0000fff) == 0x40000440)
306                 /* Rev. B 440GP, use external system clock */
307                 tb = sys_clk;
308         else
309                 /* Rev. C 440GP, errata force us to use internal clock */
310                 tb = cpu;
311
312         if (cr0 & CPC0_CR0_U0EC)
313                 /* External UART clock */
314                 uart0 = ser_clk;
315         else
316                 /* Internal UART clock */
317                 uart0 = plb / CPC0_CR0_UDIV(cr0);
318
319         if (cr0 & CPC0_CR0_U1EC)
320                 /* External UART clock */
321                 uart1 = ser_clk;
322         else
323                 /* Internal UART clock */
324                 uart1 = plb / CPC0_CR0_UDIV(cr0);
325
326         printf("PPC440GP: SysClk = %dMHz (%x)\n\r",
327                (sys_clk + 500000) / 1000000, sys_clk);
328
329         dt_fixup_cpu_clocks(cpu, tb, 0);
330
331         dt_fixup_clock("/plb", plb);
332         dt_fixup_clock("/plb/opb", opb);
333         dt_fixup_clock("/plb/opb/ebc", ebc);
334         dt_fixup_clock("/plb/opb/serial@40000200", uart0);
335         dt_fixup_clock("/plb/opb/serial@40000300", uart1);
336 }
337
338 #define SPRN_CCR1 0x378
339
340 static inline u32 __fix_zero(u32 v, u32 def)
341 {
342         return v ? v : def;
343 }
344
345 static unsigned int __ibm440eplike_fixup_clocks(unsigned int sys_clk,
346                                                 unsigned int tmr_clk,
347                                                 int per_clk_from_opb)
348 {
349         /* PLL config */
350         u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
351         u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
352
353         /* Dividers */
354         u32 fbdv   = __fix_zero((plld >> 24) & 0x1f, 32);
355         u32 fwdva  = __fix_zero((plld >> 16) & 0xf, 16);
356         u32 fwdvb  = __fix_zero((plld >> 8) & 7, 8);
357         u32 lfbdv  = __fix_zero(plld & 0x3f, 64);
358         u32 pradv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMAD) >> 24) & 7, 8);
359         u32 prbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMBD) >> 24) & 7, 8);
360         u32 opbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_OPBD) >> 24) & 3, 4);
361         u32 perdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PERD) >> 24) & 3, 4);
362
363         /* Input clocks for primary dividers */
364         u32 clk_a, clk_b;
365
366         /* Resulting clocks */
367         u32 cpu, plb, opb, ebc, vco;
368
369         /* Timebase */
370         u32 ccr1, tb = tmr_clk;
371
372         if (pllc & 0x40000000) {
373                 u32 m;
374
375                 /* Feedback path */
376                 switch ((pllc >> 24) & 7) {
377                 case 0:
378                         /* PLLOUTx */
379                         m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
380                         break;
381                 case 1:
382                         /* CPU */
383                         m = fwdva * pradv0;
384                         break;
385                 case 5:
386                         /* PERClk */
387                         m = fwdvb * prbdv0 * opbdv0 * perdv0;
388                         break;
389                 default:
390                         printf("WARNING ! Invalid PLL feedback source !\n");
391                         goto bypass;
392                 }
393                 m *= fbdv;
394                 vco = sys_clk * m;
395                 clk_a = vco / fwdva;
396                 clk_b = vco / fwdvb;
397         } else {
398 bypass:
399                 /* Bypass system PLL */
400                 vco = 0;
401                 clk_a = clk_b = sys_clk;
402         }
403
404         cpu = clk_a / pradv0;
405         plb = clk_b / prbdv0;
406         opb = plb / opbdv0;
407         ebc = (per_clk_from_opb ? opb : plb) / perdv0;
408
409         /* Figure out timebase.  Either CPU or default TmrClk */
410         ccr1 = mfspr(SPRN_CCR1);
411
412         /* If passed a 0 tmr_clk, force CPU clock */
413         if (tb == 0) {
414                 ccr1 &= ~0x80u;
415                 mtspr(SPRN_CCR1, ccr1);
416         }
417         if ((ccr1 & 0x0080) == 0)
418                 tb = cpu;
419
420         dt_fixup_cpu_clocks(cpu, tb, 0);
421         dt_fixup_clock("/plb", plb);
422         dt_fixup_clock("/plb/opb", opb);
423         dt_fixup_clock("/plb/opb/ebc", ebc);
424
425         return plb;
426 }
427
428 static void eplike_fixup_uart_clk(int index, const char *path,
429                                   unsigned int ser_clk,
430                                   unsigned int plb_clk)
431 {
432         unsigned int sdr;
433         unsigned int clock;
434
435         switch (index) {
436         case 0:
437                 sdr = SDR0_READ(DCRN_SDR0_UART0);
438                 break;
439         case 1:
440                 sdr = SDR0_READ(DCRN_SDR0_UART1);
441                 break;
442         case 2:
443                 sdr = SDR0_READ(DCRN_SDR0_UART2);
444                 break;
445         case 3:
446                 sdr = SDR0_READ(DCRN_SDR0_UART3);
447                 break;
448         default:
449                 return;
450         }
451
452         if (sdr & 0x00800000u)
453                 clock = ser_clk;
454         else
455                 clock = plb_clk / __fix_zero(sdr & 0xff, 256);
456
457         dt_fixup_clock(path, clock);
458 }
459
460 void ibm440ep_fixup_clocks(unsigned int sys_clk,
461                            unsigned int ser_clk,
462                            unsigned int tmr_clk)
463 {
464         unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0);
465
466         /* serial clocks beed fixup based on int/ext */
467         eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk);
468         eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk);
469         eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk);
470         eplike_fixup_uart_clk(3, "/plb/opb/serial@ef600600", ser_clk, plb_clk);
471 }
472
473 void ibm440gx_fixup_clocks(unsigned int sys_clk,
474                            unsigned int ser_clk,
475                            unsigned int tmr_clk)
476 {
477         unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
478
479         /* serial clocks beed fixup based on int/ext */
480         eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk);
481         eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk);
482 }
483
484 void ibm440spe_fixup_clocks(unsigned int sys_clk,
485                             unsigned int ser_clk,
486                             unsigned int tmr_clk)
487 {
488         unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
489
490         /* serial clocks beed fixup based on int/ext */
491         eplike_fixup_uart_clk(0, "/plb/opb/serial@10000200", ser_clk, plb_clk);
492         eplike_fixup_uart_clk(1, "/plb/opb/serial@10000300", ser_clk, plb_clk);
493         eplike_fixup_uart_clk(2, "/plb/opb/serial@10000600", ser_clk, plb_clk);
494 }
495
496 void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
497 {
498         u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
499         u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
500         u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
501         u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
502         u32 fwdv, fbdv, cbdv, opdv, epdv, udiv;
503
504         fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
505         fbdv = (pllmr & 0x1e000000) >> 25;
506         cbdv = ((pllmr & 0x00060000) >> 17) + 1;
507         opdv = ((pllmr & 0x00018000) >> 15) + 1;
508         epdv = ((pllmr & 0x00001800) >> 13) + 2;
509         udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
510
511         m = fwdv * fbdv * cbdv;
512
513         cpu = sys_clk * m / fwdv;
514         plb = cpu / cbdv;
515         opb = plb / opdv;
516         ebc = plb / epdv;
517
518         if (cpc0_cr0 & 0x80) {
519                 /* uart0 uses the external clock */
520                 uart0 = ser_clk;
521         } else {
522                 uart0 = cpu / udiv;
523         }
524
525         if (cpc0_cr0 & 0x40) {
526                 /* uart1 uses the external clock */
527                 uart1 = ser_clk;
528         } else {
529                 uart1 = cpu / udiv;
530         }
531
532         /* setup the timebase clock to tick at the cpu frequency */
533         cpc0_cr1 = cpc0_cr1 & ~0x00800000;
534         mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
535         tb = cpu;
536
537         dt_fixup_cpu_clocks(cpu, tb, 0);
538         dt_fixup_clock("/plb", plb);
539         dt_fixup_clock("/plb/opb", opb);
540         dt_fixup_clock("/plb/ebc", ebc);
541         dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
542         dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
543 }
544