blob: 852992b146e3c0ecf0bf1a42af348980c5015c8a [file] [log] [blame]
David Gibsonf6dfc802007-05-08 14:10:01 +10001/*
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
Josh Boyere90f3b72007-08-20 07:28:30 -050024/* Read the 4xx SDRAM controller to get size of system memory. */
25void ibm4xx_fixup_memsize(void)
David Gibsonf6dfc802007-05-08 14:10:01 +100026{
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}
David Gibson11123342007-06-13 14:52:58 +100041
Valentine Barshak606d08b2007-08-29 17:38:30 +040042/* 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
80static inline u32 mfdcr_sdram0(u32 reg)
81{
82 mtdcr(DCRN_SDRAM0_CFGADDR, reg);
83 return mfdcr(DCRN_SDRAM0_CFGDATA);
84}
85
86void 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
joe@perches.com00d70412007-12-18 06:30:12 +1100125 /* get address pins (rows) */
Valentine Barshak606d08b2007-08-29 17:38:30 +0400126 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
Josh Boyere90f3b72007-08-20 07:28:30 -0500150#define SPRN_DBCR0_40X 0x3F2
151#define SPRN_DBCR0_44X 0x134
152#define DBCR0_RST_SYSTEM 0x30000000
David Gibson11123342007-06-13 14:52:58 +1000153
154void 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"
Josh Boyere90f3b72007-08-20 07:28:30 -0500162 : "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM)
David Gibson11123342007-06-13 14:52:58 +1000163 );
164
165}
David Gibsonb2ba34f2007-06-13 14:52:59 +1000166
Josh Boyere90f3b72007-08-20 07:28:30 -0500167void 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
180void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1)
181{
Benjamin Herrenschmidt61974032007-12-21 15:39:26 +1100182 /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
183 * do this for us
184 */
Josh Boyere90f3b72007-08-20 07:28:30 -0500185 if (emac0)
186 *emac0 = EMAC_RESET;
187 if (emac1)
188 *emac1 = EMAC_RESET;
189
190 mtdcr(DCRN_MAL0_CFG, MAL_RESET);
Benjamin Herrenschmidt61974032007-12-21 15:39:26 +1100191 while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET) {};
Josh Boyere90f3b72007-08-20 07:28:30 -0500192}
193
David Gibsonb2ba34f2007-06-13 14:52:59 +1000194/* Read 4xx EBC bus bridge registers to get mappings of the peripheral
195 * banks into the OPB address space */
196void ibm4xx_fixup_ebc_ranges(const char *ebc)
197{
198 void *devp;
199 u32 bxcr;
200 u32 ranges[EBC_NUM_BANKS*4];
201 u32 *p = ranges;
202 int i;
203
204 for (i = 0; i < EBC_NUM_BANKS; i++) {
205 mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i));
206 bxcr = mfdcr(DCRN_EBC0_CFGDATA);
207
208 if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) {
209 *p++ = i;
210 *p++ = 0;
211 *p++ = bxcr & EBC_BXCR_BAS;
212 *p++ = EBC_BXCR_BANK_SIZE(bxcr);
213 }
214 }
215
216 devp = finddevice(ebc);
217 if (! devp)
218 fatal("Couldn't locate EBC node %s\n\r", ebc);
219
220 setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32));
221}
Josh Boyer2ba45732007-08-20 07:30:32 -0500222
223#define SPRN_CCR1 0x378
224void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
225{
226 u32 cpu, plb, opb, ebc, tb, uart0, m, vco;
227 u32 reg;
228 u32 fwdva, fwdvb, fbdv, lfbdv, opbdv0, perdv0, spcid0, prbdv0, tmp;
229
230 mtdcr(DCRN_CPR0_ADDR, CPR0_PLLD0);
231 reg = mfdcr(DCRN_CPR0_DATA);
232 tmp = (reg & 0x000F0000) >> 16;
233 fwdva = tmp ? tmp : 16;
234 tmp = (reg & 0x00000700) >> 8;
235 fwdvb = tmp ? tmp : 8;
236 tmp = (reg & 0x1F000000) >> 24;
237 fbdv = tmp ? tmp : 32;
238 lfbdv = (reg & 0x0000007F);
239
240 mtdcr(DCRN_CPR0_ADDR, CPR0_OPBD0);
241 reg = mfdcr(DCRN_CPR0_DATA);
242 tmp = (reg & 0x03000000) >> 24;
243 opbdv0 = tmp ? tmp : 4;
244
245 mtdcr(DCRN_CPR0_ADDR, CPR0_PERD0);
246 reg = mfdcr(DCRN_CPR0_DATA);
247 tmp = (reg & 0x07000000) >> 24;
248 perdv0 = tmp ? tmp : 8;
249
250 mtdcr(DCRN_CPR0_ADDR, CPR0_PRIMBD0);
251 reg = mfdcr(DCRN_CPR0_DATA);
252 tmp = (reg & 0x07000000) >> 24;
253 prbdv0 = tmp ? tmp : 8;
254
255 mtdcr(DCRN_CPR0_ADDR, CPR0_SCPID);
256 reg = mfdcr(DCRN_CPR0_DATA);
257 tmp = (reg & 0x03000000) >> 24;
258 spcid0 = tmp ? tmp : 4;
259
260 /* Calculate M */
261 mtdcr(DCRN_CPR0_ADDR, CPR0_PLLC0);
262 reg = mfdcr(DCRN_CPR0_DATA);
263 tmp = (reg & 0x03000000) >> 24;
264 if (tmp == 0) { /* PLL output */
265 tmp = (reg & 0x20000000) >> 29;
266 if (!tmp) /* PLLOUTA */
267 m = fbdv * lfbdv * fwdva;
268 else
269 m = fbdv * lfbdv * fwdvb;
270 }
271 else if (tmp == 1) /* CPU output */
272 m = fbdv * fwdva;
273 else
274 m = perdv0 * opbdv0 * fwdvb;
275
276 vco = (m * sysclk) + (m >> 1);
277 cpu = vco / fwdva;
278 plb = vco / fwdvb / prbdv0;
279 opb = plb / opbdv0;
280 ebc = plb / perdv0;
281
282 /* FIXME */
283 uart0 = ser_clk;
284
285 /* Figure out timebase. Either CPU or default TmrClk */
286 asm volatile (
287 "mfspr %0,%1\n"
288 :
289 "=&r"(reg) : "i"(SPRN_CCR1));
290 if (reg & 0x0080)
291 tb = 25000000; /* TmrClk is 25MHz */
292 else
293 tb = cpu;
294
295 dt_fixup_cpu_clocks(cpu, tb, 0);
296 dt_fixup_clock("/plb", plb);
297 dt_fixup_clock("/plb/opb", opb);
298 dt_fixup_clock("/plb/opb/ebc", ebc);
299 dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
300 dt_fixup_clock("/plb/opb/serial@ef600400", uart0);
301 dt_fixup_clock("/plb/opb/serial@ef600500", uart0);
302 dt_fixup_clock("/plb/opb/serial@ef600600", uart0);
303}
Benjamin Herrenschmidt61974032007-12-21 15:39:26 +1100304
305void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
306{
307 u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
308 u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
309 u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
310 u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
311 u32 fwdv, fbdv, cbdv, opdv, epdv, udiv;
312
313 fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
314 fbdv = (pllmr & 0x1e000000) >> 25;
315 cbdv = ((pllmr & 0x00060000) >> 17) + 1;
316 opdv = ((pllmr & 0x00018000) >> 15) + 1;
317 epdv = ((pllmr & 0x00001800) >> 13) + 2;
318 udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
319
320 m = fwdv * fbdv * cbdv;
321
322 cpu = sysclk * m / fwdv;
323 plb = cpu / cbdv;
324 opb = plb / opdv;
325 ebc = plb / epdv;
326
327 if (cpc0_cr0 & 0x80) {
328 /* uart0 uses the external clock */
329 uart0 = ser_clk;
330 } else {
331 uart0 = cpu / udiv;
332 }
333
334 if (cpc0_cr0 & 0x40) {
335 /* uart1 uses the external clock */
336 uart1 = ser_clk;
337 } else {
338 uart1 = cpu / udiv;
339 }
340
341 /* setup the timebase clock to tick at the cpu frequency */
342 cpc0_cr1 = cpc0_cr1 & ~0x00800000;
343 mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
344 tb = cpu;
345
346 dt_fixup_cpu_clocks(cpu, tb, 0);
347 dt_fixup_clock("/plb", plb);
348 dt_fixup_clock("/plb/opb", opb);
349 dt_fixup_clock("/plb/ebc", ebc);
350 dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
351 dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
352}
353