diff options
Diffstat (limited to 'arch/powerpc/boot/4xx.c')
-rw-r--r-- | arch/powerpc/boot/4xx.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c new file mode 100644 index 000000000000..ebf9e217612d --- /dev/null +++ b/arch/powerpc/boot/4xx.c | |||
@@ -0,0 +1,300 @@ | |||
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_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 | mtdcr(DCRN_SDRAM0_CFGADDR, sdram_bxcr[i]); | ||
33 | bank_config = mfdcr(DCRN_SDRAM0_CFGDATA); | ||
34 | |||
35 | if (bank_config & SDRAM_CONFIG_BANK_ENABLE) | ||
36 | memsize += SDRAM_CONFIG_BANK_SIZE(bank_config); | ||
37 | } | ||
38 | |||
39 | dt_fixup_memory(0, memsize); | ||
40 | } | ||
41 | |||
42 | /* 4xx DDR1/2 Denali memory controller support */ | ||
43 | /* DDR0 registers */ | ||
44 | #define DDR0_02 2 | ||
45 | #define DDR0_08 8 | ||
46 | #define DDR0_10 10 | ||
47 | #define DDR0_14 14 | ||
48 | #define DDR0_42 42 | ||
49 | #define DDR0_43 43 | ||
50 | |||
51 | /* DDR0_02 */ | ||
52 | #define DDR_START 0x1 | ||
53 | #define DDR_START_SHIFT 0 | ||
54 | #define DDR_MAX_CS_REG 0x3 | ||
55 | #define DDR_MAX_CS_REG_SHIFT 24 | ||
56 | #define DDR_MAX_COL_REG 0xf | ||
57 | #define DDR_MAX_COL_REG_SHIFT 16 | ||
58 | #define DDR_MAX_ROW_REG 0xf | ||
59 | #define DDR_MAX_ROW_REG_SHIFT 8 | ||
60 | /* DDR0_08 */ | ||
61 | #define DDR_DDR2_MODE 0x1 | ||
62 | #define DDR_DDR2_MODE_SHIFT 0 | ||
63 | /* DDR0_10 */ | ||
64 | #define DDR_CS_MAP 0x3 | ||
65 | #define DDR_CS_MAP_SHIFT 8 | ||
66 | /* DDR0_14 */ | ||
67 | #define DDR_REDUC 0x1 | ||
68 | #define DDR_REDUC_SHIFT 16 | ||
69 | /* DDR0_42 */ | ||
70 | #define DDR_APIN 0x7 | ||
71 | #define DDR_APIN_SHIFT 24 | ||
72 | /* DDR0_43 */ | ||
73 | #define DDR_COL_SZ 0x7 | ||
74 | #define DDR_COL_SZ_SHIFT 8 | ||
75 | #define DDR_BANK8 0x1 | ||
76 | #define DDR_BANK8_SHIFT 0 | ||
77 | |||
78 | #define DDR_GET_VAL(val, mask, shift) (((val) >> (shift)) & (mask)) | ||
79 | |||
80 | static inline u32 mfdcr_sdram0(u32 reg) | ||
81 | { | ||
82 | mtdcr(DCRN_SDRAM0_CFGADDR, reg); | ||
83 | return mfdcr(DCRN_SDRAM0_CFGDATA); | ||
84 | } | ||
85 | |||
86 | void ibm4xx_denali_fixup_memsize(void) | ||
87 | { | ||
88 | u32 val, max_cs, max_col, max_row; | ||
89 | u32 cs, col, row, bank, dpath; | ||
90 | unsigned long memsize; | ||
91 | |||
92 | val = mfdcr_sdram0(DDR0_02); | ||
93 | if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT)) | ||
94 | fatal("DDR controller is not initialized\n"); | ||
95 | |||
96 | /* get maximum cs col and row values */ | ||
97 | max_cs = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT); | ||
98 | max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT); | ||
99 | max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT); | ||
100 | |||
101 | /* get CS value */ | ||
102 | val = mfdcr_sdram0(DDR0_10); | ||
103 | |||
104 | val = DDR_GET_VAL(val, DDR_CS_MAP, DDR_CS_MAP_SHIFT); | ||
105 | cs = 0; | ||
106 | while (val) { | ||
107 | if (val && 0x1) | ||
108 | cs++; | ||
109 | val = val >> 1; | ||
110 | } | ||
111 | |||
112 | if (!cs) | ||
113 | fatal("No memory installed\n"); | ||
114 | if (cs > max_cs) | ||
115 | fatal("DDR wrong CS configuration\n"); | ||
116 | |||
117 | /* get data path bytes */ | ||
118 | val = mfdcr_sdram0(DDR0_14); | ||
119 | |||
120 | if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT)) | ||
121 | dpath = 8; /* 64 bits */ | ||
122 | else | ||
123 | dpath = 4; /* 32 bits */ | ||
124 | |||
125 | /* get adress pins (rows) */ | ||
126 | val = mfdcr_sdram0(DDR0_42); | ||
127 | |||
128 | row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT); | ||
129 | if (row > max_row) | ||
130 | fatal("DDR wrong APIN configuration\n"); | ||
131 | row = max_row - row; | ||
132 | |||
133 | /* get collomn size and banks */ | ||
134 | val = mfdcr_sdram0(DDR0_43); | ||
135 | |||
136 | col = DDR_GET_VAL(val, DDR_COL_SZ, DDR_COL_SZ_SHIFT); | ||
137 | if (col > max_col) | ||
138 | fatal("DDR wrong COL configuration\n"); | ||
139 | col = max_col - col; | ||
140 | |||
141 | if (DDR_GET_VAL(val, DDR_BANK8, DDR_BANK8_SHIFT)) | ||
142 | bank = 8; /* 8 banks */ | ||
143 | else | ||
144 | bank = 4; /* 4 banks */ | ||
145 | |||
146 | memsize = cs * (1 << (col+row)) * bank * dpath; | ||
147 | dt_fixup_memory(0, memsize); | ||
148 | } | ||
149 | |||
150 | #define SPRN_DBCR0_40X 0x3F2 | ||
151 | #define SPRN_DBCR0_44X 0x134 | ||
152 | #define DBCR0_RST_SYSTEM 0x30000000 | ||
153 | |||
154 | void ibm44x_dbcr_reset(void) | ||
155 | { | ||
156 | unsigned long tmp; | ||
157 | |||
158 | asm volatile ( | ||
159 | "mfspr %0,%1\n" | ||
160 | "oris %0,%0,%2@h\n" | ||
161 | "mtspr %1,%0" | ||
162 | : "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM) | ||
163 | ); | ||
164 | |||
165 | } | ||
166 | |||
167 | void ibm40x_dbcr_reset(void) | ||
168 | { | ||
169 | unsigned long tmp; | ||
170 | |||
171 | asm volatile ( | ||
172 | "mfspr %0,%1\n" | ||
173 | "oris %0,%0,%2@h\n" | ||
174 | "mtspr %1,%0" | ||
175 | : "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM) | ||
176 | ); | ||
177 | } | ||
178 | |||
179 | #define EMAC_RESET 0x20000000 | ||
180 | void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1) | ||
181 | { | ||
182 | /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't do this for us */ | ||
183 | if (emac0) | ||
184 | *emac0 = EMAC_RESET; | ||
185 | if (emac1) | ||
186 | *emac1 = EMAC_RESET; | ||
187 | |||
188 | mtdcr(DCRN_MAL0_CFG, MAL_RESET); | ||
189 | } | ||
190 | |||
191 | /* Read 4xx EBC bus bridge registers to get mappings of the peripheral | ||
192 | * banks into the OPB address space */ | ||
193 | void ibm4xx_fixup_ebc_ranges(const char *ebc) | ||
194 | { | ||
195 | void *devp; | ||
196 | u32 bxcr; | ||
197 | u32 ranges[EBC_NUM_BANKS*4]; | ||
198 | u32 *p = ranges; | ||
199 | int i; | ||
200 | |||
201 | for (i = 0; i < EBC_NUM_BANKS; i++) { | ||
202 | mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i)); | ||
203 | bxcr = mfdcr(DCRN_EBC0_CFGDATA); | ||
204 | |||
205 | if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) { | ||
206 | *p++ = i; | ||
207 | *p++ = 0; | ||
208 | *p++ = bxcr & EBC_BXCR_BAS; | ||
209 | *p++ = EBC_BXCR_BANK_SIZE(bxcr); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | devp = finddevice(ebc); | ||
214 | if (! devp) | ||
215 | fatal("Couldn't locate EBC node %s\n\r", ebc); | ||
216 | |||
217 | setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32)); | ||
218 | } | ||
219 | |||
220 | #define SPRN_CCR1 0x378 | ||
221 | void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) | ||
222 | { | ||
223 | u32 cpu, plb, opb, ebc, tb, uart0, m, vco; | ||
224 | u32 reg; | ||
225 | u32 fwdva, fwdvb, fbdv, lfbdv, opbdv0, perdv0, spcid0, prbdv0, tmp; | ||
226 | |||
227 | mtdcr(DCRN_CPR0_ADDR, CPR0_PLLD0); | ||
228 | reg = mfdcr(DCRN_CPR0_DATA); | ||
229 | tmp = (reg & 0x000F0000) >> 16; | ||
230 | fwdva = tmp ? tmp : 16; | ||
231 | tmp = (reg & 0x00000700) >> 8; | ||
232 | fwdvb = tmp ? tmp : 8; | ||
233 | tmp = (reg & 0x1F000000) >> 24; | ||
234 | fbdv = tmp ? tmp : 32; | ||
235 | lfbdv = (reg & 0x0000007F); | ||
236 | |||
237 | mtdcr(DCRN_CPR0_ADDR, CPR0_OPBD0); | ||
238 | reg = mfdcr(DCRN_CPR0_DATA); | ||
239 | tmp = (reg & 0x03000000) >> 24; | ||
240 | opbdv0 = tmp ? tmp : 4; | ||
241 | |||
242 | mtdcr(DCRN_CPR0_ADDR, CPR0_PERD0); | ||
243 | reg = mfdcr(DCRN_CPR0_DATA); | ||
244 | tmp = (reg & 0x07000000) >> 24; | ||
245 | perdv0 = tmp ? tmp : 8; | ||
246 | |||
247 | mtdcr(DCRN_CPR0_ADDR, CPR0_PRIMBD0); | ||
248 | reg = mfdcr(DCRN_CPR0_DATA); | ||
249 | tmp = (reg & 0x07000000) >> 24; | ||
250 | prbdv0 = tmp ? tmp : 8; | ||
251 | |||
252 | mtdcr(DCRN_CPR0_ADDR, CPR0_SCPID); | ||
253 | reg = mfdcr(DCRN_CPR0_DATA); | ||
254 | tmp = (reg & 0x03000000) >> 24; | ||
255 | spcid0 = tmp ? tmp : 4; | ||
256 | |||
257 | /* Calculate M */ | ||
258 | mtdcr(DCRN_CPR0_ADDR, CPR0_PLLC0); | ||
259 | reg = mfdcr(DCRN_CPR0_DATA); | ||
260 | tmp = (reg & 0x03000000) >> 24; | ||
261 | if (tmp == 0) { /* PLL output */ | ||
262 | tmp = (reg & 0x20000000) >> 29; | ||
263 | if (!tmp) /* PLLOUTA */ | ||
264 | m = fbdv * lfbdv * fwdva; | ||
265 | else | ||
266 | m = fbdv * lfbdv * fwdvb; | ||
267 | } | ||
268 | else if (tmp == 1) /* CPU output */ | ||
269 | m = fbdv * fwdva; | ||
270 | else | ||
271 | m = perdv0 * opbdv0 * fwdvb; | ||
272 | |||
273 | vco = (m * sysclk) + (m >> 1); | ||
274 | cpu = vco / fwdva; | ||
275 | plb = vco / fwdvb / prbdv0; | ||
276 | opb = plb / opbdv0; | ||
277 | ebc = plb / perdv0; | ||
278 | |||
279 | /* FIXME */ | ||
280 | uart0 = ser_clk; | ||
281 | |||
282 | /* Figure out timebase. Either CPU or default TmrClk */ | ||
283 | asm volatile ( | ||
284 | "mfspr %0,%1\n" | ||
285 | : | ||
286 | "=&r"(reg) : "i"(SPRN_CCR1)); | ||
287 | if (reg & 0x0080) | ||
288 | tb = 25000000; /* TmrClk is 25MHz */ | ||
289 | else | ||
290 | tb = cpu; | ||
291 | |||
292 | dt_fixup_cpu_clocks(cpu, tb, 0); | ||
293 | dt_fixup_clock("/plb", plb); | ||
294 | dt_fixup_clock("/plb/opb", opb); | ||
295 | dt_fixup_clock("/plb/opb/ebc", ebc); | ||
296 | dt_fixup_clock("/plb/opb/serial@ef600300", uart0); | ||
297 | dt_fixup_clock("/plb/opb/serial@ef600400", uart0); | ||
298 | dt_fixup_clock("/plb/opb/serial@ef600500", uart0); | ||
299 | dt_fixup_clock("/plb/opb/serial@ef600600", uart0); | ||
300 | } | ||