]>
Commit | Line | Data |
---|---|---|
e6f2e902 MB |
1 | /* |
2 | * (C) Copyright 2005 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | #include <common.h> | |
26 | #include <ioports.h> | |
27 | #include <mpc83xx.h> | |
28 | #include <asm/mpc8349_pci.h> | |
29 | #include <i2c.h> | |
e6f2e902 MB |
30 | #include <miiphy.h> |
31 | #include <asm-ppc/mmu.h> | |
e6f2e902 | 32 | #include <pci.h> |
e6f2e902 | 33 | |
d87080b7 WD |
34 | DECLARE_GLOBAL_DATA_PTR; |
35 | ||
e6f2e902 MB |
36 | #define IOSYNC asm("eieio") |
37 | #define ISYNC asm("isync") | |
38 | #define SYNC asm("sync") | |
39 | #define FPW FLASH_PORT_WIDTH | |
40 | #define FPWV FLASH_PORT_WIDTHV | |
41 | ||
42 | #define DDR_MAX_SIZE_PER_CS 0x20000000 | |
43 | ||
44 | #if defined(DDR_CASLAT_20) | |
45 | #define TIMING_CASLAT TIMING_CFG1_CASLAT_20 | |
46 | #define MODE_CASLAT DDR_MODE_CASLAT_20 | |
47 | #else | |
48 | #define TIMING_CASLAT TIMING_CFG1_CASLAT_25 | |
49 | #define MODE_CASLAT DDR_MODE_CASLAT_25 | |
50 | #endif | |
51 | ||
52 | #define INITIAL_CS_CONFIG (CSCONFIG_EN | CSCONFIG_ROW_BIT_12 | \ | |
53 | CSCONFIG_COL_BIT_9) | |
54 | ||
55 | /* Global variable used to store detected number of banks */ | |
56 | int tqm834x_num_flash_banks; | |
57 | ||
58 | /* External definitions */ | |
59 | ulong flash_get_size (ulong base, int banknum); | |
60 | extern flash_info_t flash_info[]; | |
e6f2e902 MB |
61 | |
62 | /* Local functions */ | |
63 | static int detect_num_flash_banks(void); | |
64 | static long int get_ddr_bank_size(short cs, volatile long *base); | |
65 | static void set_cs_bounds(short cs, long base, long size); | |
66 | static void set_cs_config(short cs, long config); | |
67 | static void set_ddr_config(void); | |
68 | ||
69 | /* Local variable */ | |
6d0f6bcf | 70 | static volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
e6f2e902 MB |
71 | |
72 | /************************************************************************** | |
73 | * Board initialzation after relocation to RAM. Used to detect the number | |
74 | * of Flash banks on TQM834x. | |
75 | */ | |
76 | int board_early_init_r (void) { | |
77 | /* sanity check, IMMARBAR should be mirrored at offset zero of IMMR */ | |
78 | if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32)im) | |
79 | return 0; | |
f013dacf | 80 | |
e6f2e902 MB |
81 | /* detect the number of Flash banks */ |
82 | return detect_num_flash_banks(); | |
83 | } | |
84 | ||
85 | /************************************************************************** | |
86 | * DRAM initalization and size detection | |
87 | */ | |
9973e3c6 | 88 | phys_size_t initdram (int board_type) |
e6f2e902 MB |
89 | { |
90 | long bank_size; | |
91 | long size; | |
92 | int cs; | |
93 | ||
94 | /* during size detection, set up the max DDRLAW size */ | |
6d0f6bcf | 95 | im->sysconf.ddrlaw[0].bar = CONFIG_SYS_DDR_BASE; |
e6f2e902 MB |
96 | im->sysconf.ddrlaw[0].ar = (LAWAR_EN | LAWAR_SIZE_2G); |
97 | ||
98 | /* set CS bounds to maximum size */ | |
99 | for(cs = 0; cs < 4; ++cs) { | |
100 | set_cs_bounds(cs, | |
6d0f6bcf | 101 | CONFIG_SYS_DDR_BASE + (cs * DDR_MAX_SIZE_PER_CS), |
e6f2e902 MB |
102 | DDR_MAX_SIZE_PER_CS); |
103 | ||
104 | set_cs_config(cs, INITIAL_CS_CONFIG); | |
105 | } | |
106 | ||
107 | /* configure ddr controller */ | |
108 | set_ddr_config(); | |
109 | ||
110 | udelay(200); | |
f013dacf | 111 | |
e6f2e902 MB |
112 | /* enable DDR controller */ |
113 | im->ddr.sdram_cfg = (SDRAM_CFG_MEM_EN | | |
114 | SDRAM_CFG_SREN | | |
bbea46f7 | 115 | SDRAM_CFG_SDRAM_TYPE_DDR1); |
e6f2e902 MB |
116 | SYNC; |
117 | ||
118 | /* size detection */ | |
119 | debug("\n"); | |
120 | size = 0; | |
121 | for(cs = 0; cs < 4; ++cs) { | |
122 | debug("\nDetecting Bank%d\n", cs); | |
123 | ||
124 | bank_size = get_ddr_bank_size(cs, | |
6d0f6bcf | 125 | (volatile long*)(CONFIG_SYS_DDR_BASE + size)); |
e6f2e902 MB |
126 | size += bank_size; |
127 | ||
128 | debug("DDR Bank%d size: %d MiB\n\n", cs, bank_size >> 20); | |
129 | ||
130 | /* exit if less than one bank */ | |
131 | if(size < DDR_MAX_SIZE_PER_CS) break; | |
132 | } | |
133 | ||
134 | return size; | |
135 | } | |
136 | ||
137 | /************************************************************************** | |
138 | * checkboard() | |
139 | */ | |
140 | int checkboard (void) | |
141 | { | |
142 | puts("Board: TQM834x\n"); | |
143 | ||
144 | #ifdef CONFIG_PCI | |
6902df56 RJ |
145 | volatile immap_t * immr; |
146 | u32 w, f; | |
e6f2e902 | 147 | |
6d0f6bcf | 148 | immr = (immap_t *)CONFIG_SYS_IMMR; |
e080313c | 149 | if (!(immr->reset.rcwh & HRCWH_PCI_HOST)) { |
6902df56 RJ |
150 | printf("PCI: NOT in host mode..?!\n"); |
151 | return 0; | |
152 | } | |
e6f2e902 | 153 | |
6902df56 RJ |
154 | /* get bus width */ |
155 | w = 32; | |
e080313c | 156 | if (immr->reset.rcwh & HRCWH_64_BIT_PCI) |
6902df56 | 157 | w = 64; |
e6f2e902 | 158 | |
6902df56 RJ |
159 | /* get clock */ |
160 | f = gd->pci_clk; | |
e6f2e902 | 161 | |
6902df56 RJ |
162 | printf("PCI1: %d bit, %d MHz\n", w, f / 1000000); |
163 | #else | |
164 | printf("PCI: disabled\n"); | |
165 | #endif | |
166 | return 0; | |
e6f2e902 MB |
167 | } |
168 | ||
6902df56 | 169 | |
e6f2e902 MB |
170 | /************************************************************************** |
171 | * | |
172 | * Local functions | |
173 | * | |
174 | *************************************************************************/ | |
175 | ||
176 | /************************************************************************** | |
177 | * Detect the number of flash banks (1 or 2). Store it in | |
178 | * a global variable tqm834x_num_flash_banks. | |
179 | * Bank detection code based on the Monitor code. | |
180 | */ | |
181 | static int detect_num_flash_banks(void) | |
182 | { | |
183 | typedef unsigned long FLASH_PORT_WIDTH; | |
184 | typedef volatile unsigned long FLASH_PORT_WIDTHV; | |
185 | FPWV *bank1_base; | |
186 | FPWV *bank2_base; | |
187 | FPW bank1_read; | |
188 | FPW bank2_read; | |
189 | ulong bank1_size; | |
190 | ulong bank2_size; | |
191 | ulong total_size; | |
192 | ||
193 | tqm834x_num_flash_banks = 2; /* assume two banks */ | |
f013dacf | 194 | |
e6f2e902 | 195 | /* Get bank 1 and 2 information */ |
6d0f6bcf | 196 | bank1_size = flash_get_size(CONFIG_SYS_FLASH_BASE, 0); |
e6f2e902 | 197 | debug("Bank1 size: %lu\n", bank1_size); |
6d0f6bcf | 198 | bank2_size = flash_get_size(CONFIG_SYS_FLASH_BASE + bank1_size, 1); |
e6f2e902 MB |
199 | debug("Bank2 size: %lu\n", bank2_size); |
200 | total_size = bank1_size + bank2_size; | |
201 | ||
202 | if (bank2_size > 0) { | |
203 | /* Seems like we've got bank 2, but maybe it's mirrored 1 */ | |
204 | ||
205 | /* Set the base addresses */ | |
6d0f6bcf JCPV |
206 | bank1_base = (FPWV *) (CONFIG_SYS_FLASH_BASE); |
207 | bank2_base = (FPWV *) (CONFIG_SYS_FLASH_BASE + bank1_size); | |
e6f2e902 MB |
208 | |
209 | /* Put bank 2 into CFI command mode and read */ | |
210 | bank2_base[0x55] = 0x00980098; | |
211 | IOSYNC; | |
212 | ISYNC; | |
213 | bank2_read = bank2_base[0x10]; | |
214 | ||
215 | /* Read from bank 1 (it's in read mode) */ | |
216 | bank1_read = bank1_base[0x10]; | |
217 | ||
218 | /* Reset Flash */ | |
219 | bank1_base[0] = 0x00F000F0; | |
220 | bank2_base[0] = 0x00F000F0; | |
221 | ||
222 | if (bank2_read == bank1_read) { | |
223 | /* | |
224 | * Looks like just one bank, but not sure yet. Let's | |
225 | * read from bank 2 in autosoelect mode. | |
226 | */ | |
227 | bank2_base[0x0555] = 0x00AA00AA; | |
228 | bank2_base[0x02AA] = 0x00550055; | |
229 | bank2_base[0x0555] = 0x00900090; | |
230 | IOSYNC; | |
231 | ISYNC; | |
232 | bank2_read = bank2_base[0x10]; | |
233 | ||
234 | /* Read from bank 1 (it's in read mode) */ | |
235 | bank1_read = bank1_base[0x10]; | |
236 | ||
237 | /* Reset Flash */ | |
238 | bank1_base[0] = 0x00F000F0; | |
239 | bank2_base[0] = 0x00F000F0; | |
240 | ||
241 | if (bank2_read == bank1_read) { | |
242 | /* | |
243 | * In both CFI command and autoselect modes, | |
244 | * we got the some data reading from Flash. | |
245 | * There is only one mirrored bank. | |
246 | */ | |
247 | tqm834x_num_flash_banks = 1; | |
248 | total_size = bank1_size; | |
249 | } | |
250 | } | |
251 | } | |
252 | ||
253 | debug("Number of flash banks detected: %d\n", tqm834x_num_flash_banks); | |
254 | ||
255 | /* set OR0 and BR0 */ | |
6d0f6bcf | 256 | im->lbus.bank[0].or = CONFIG_SYS_OR_TIMING_FLASH | |
e6f2e902 | 257 | (-(total_size) & OR_GPCM_AM); |
6d0f6bcf | 258 | im->lbus.bank[0].br = (CONFIG_SYS_FLASH_BASE & BR_BA) | |
e6f2e902 MB |
259 | (BR_MS_GPCM | BR_PS_32 | BR_V); |
260 | ||
261 | return (0); | |
262 | } | |
263 | ||
264 | /************************************************************************* | |
265 | * Detect the size of a ddr bank. Sets CS bounds and CS config accordingly. | |
266 | */ | |
267 | static long int get_ddr_bank_size(short cs, volatile long *base) | |
268 | { | |
269 | /* This array lists all valid DDR SDRAM configurations, with | |
270 | * Bank sizes in bytes. (Refer to Table 9-27 in the MPC8349E RM). | |
271 | * The last entry has to to have size equal 0 and is igonred during | |
272 | * autodection. Bank sizes must be in increasing order of size | |
273 | */ | |
274 | struct { | |
275 | long row; | |
276 | long col; | |
277 | long size; | |
278 | } conf[] = { | |
279 | {CSCONFIG_ROW_BIT_12, CSCONFIG_COL_BIT_8, 32 << 20}, | |
280 | {CSCONFIG_ROW_BIT_12, CSCONFIG_COL_BIT_9, 64 << 20}, | |
281 | {CSCONFIG_ROW_BIT_12, CSCONFIG_COL_BIT_10, 128 << 20}, | |
282 | {CSCONFIG_ROW_BIT_13, CSCONFIG_COL_BIT_9, 128 << 20}, | |
283 | {CSCONFIG_ROW_BIT_13, CSCONFIG_COL_BIT_10, 256 << 20}, | |
284 | {CSCONFIG_ROW_BIT_13, CSCONFIG_COL_BIT_11, 512 << 20}, | |
285 | {CSCONFIG_ROW_BIT_14, CSCONFIG_COL_BIT_10, 512 << 20}, | |
286 | {CSCONFIG_ROW_BIT_14, CSCONFIG_COL_BIT_11, 1024 << 20}, | |
287 | {0, 0, 0} | |
288 | }; | |
289 | ||
290 | int i; | |
291 | int detected; | |
292 | long size; | |
293 | ||
294 | detected = -1; | |
295 | for(i = 0; conf[i].size != 0; ++i) { | |
296 | ||
297 | /* set sdram bank configuration */ | |
298 | set_cs_config(cs, CSCONFIG_EN | conf[i].col | conf[i].row); | |
299 | ||
300 | debug("Getting RAM size...\n"); | |
301 | size = get_ram_size(base, DDR_MAX_SIZE_PER_CS); | |
302 | ||
303 | if((size == conf[i].size) && (i == detected + 1)) | |
304 | detected = i; | |
305 | ||
306 | debug("Trying %ld x %ld (%ld MiB) at addr %p, detected: %ld MiB\n", | |
307 | conf[i].row, | |
308 | conf[i].col, | |
309 | conf[i].size >> 20, | |
310 | base, | |
311 | size >> 20); | |
312 | } | |
313 | ||
314 | if(detected == -1){ | |
315 | /* disable empty cs */ | |
316 | debug("\nNo valid configurations for CS%d, disabling...\n", cs); | |
317 | set_cs_config(cs, 0); | |
318 | return 0; | |
319 | } | |
f013dacf | 320 | |
e6f2e902 MB |
321 | debug("\nDetected configuration %ld x %ld (%ld MiB) at addr %p\n", |
322 | conf[detected].row, conf[detected].col, conf[detected].size >> 20, base); | |
f013dacf | 323 | |
e6f2e902 MB |
324 | /* configure cs ro detected params */ |
325 | set_cs_config(cs, CSCONFIG_EN | conf[detected].row | | |
326 | conf[detected].col); | |
327 | ||
328 | set_cs_bounds(cs, (long)base, conf[detected].size); | |
329 | ||
330 | return(conf[detected].size); | |
331 | } | |
332 | ||
333 | /************************************************************************** | |
334 | * Sets DDR bank CS bounds. | |
335 | */ | |
336 | static void set_cs_bounds(short cs, long base, long size) | |
337 | { | |
338 | debug("Setting bounds %08x, %08x for cs %d\n", base, size, cs); | |
339 | if(size == 0){ | |
340 | im->ddr.csbnds[cs].csbnds = 0x00000000; | |
341 | } else { | |
342 | im->ddr.csbnds[cs].csbnds = | |
343 | ((base >> CSBNDS_SA_SHIFT) & CSBNDS_SA) | | |
344 | (((base + size - 1) >> CSBNDS_EA_SHIFT) & | |
345 | CSBNDS_EA); | |
346 | } | |
347 | SYNC; | |
348 | } | |
349 | ||
350 | /************************************************************************** | |
351 | * Sets DDR banks CS configuration. | |
352 | * config == 0x00000000 disables the CS. | |
353 | */ | |
354 | static void set_cs_config(short cs, long config) | |
355 | { | |
356 | debug("Setting config %08x for cs %d\n", config, cs); | |
357 | im->ddr.cs_config[cs] = config; | |
358 | SYNC; | |
359 | } | |
360 | ||
361 | /************************************************************************** | |
362 | * Sets DDR clocks, timings and configuration. | |
363 | */ | |
364 | static void set_ddr_config(void) { | |
365 | /* clock control */ | |
366 | im->ddr.sdram_clk_cntl = DDR_SDRAM_CLK_CNTL_SS_EN | | |
367 | DDR_SDRAM_CLK_CNTL_CLK_ADJUST_05; | |
368 | SYNC; | |
f013dacf | 369 | |
e6f2e902 MB |
370 | /* timing configuration */ |
371 | im->ddr.timing_cfg_1 = | |
372 | (4 << TIMING_CFG1_PRETOACT_SHIFT) | | |
373 | (7 << TIMING_CFG1_ACTTOPRE_SHIFT) | | |
374 | (4 << TIMING_CFG1_ACTTORW_SHIFT) | | |
375 | (5 << TIMING_CFG1_REFREC_SHIFT) | | |
376 | (3 << TIMING_CFG1_WRREC_SHIFT) | | |
377 | (3 << TIMING_CFG1_ACTTOACT_SHIFT) | | |
378 | (1 << TIMING_CFG1_WRTORD_SHIFT) | | |
379 | (TIMING_CFG1_CASLAT & TIMING_CASLAT); | |
380 | ||
381 | im->ddr.timing_cfg_2 = | |
382 | TIMING_CFG2_CPO_DEF | | |
383 | (2 << TIMING_CFG2_WR_DATA_DELAY_SHIFT); | |
384 | SYNC; | |
385 | ||
386 | /* don't enable DDR controller yet */ | |
387 | im->ddr.sdram_cfg = | |
388 | SDRAM_CFG_SREN | | |
bbea46f7 | 389 | SDRAM_CFG_SDRAM_TYPE_DDR1; |
e6f2e902 | 390 | SYNC; |
f013dacf | 391 | |
e6f2e902 MB |
392 | /* Set SDRAM mode */ |
393 | im->ddr.sdram_mode = | |
394 | ((DDR_MODE_EXT_MODEREG | DDR_MODE_WEAK) << | |
395 | SDRAM_MODE_ESD_SHIFT) | | |
396 | ((DDR_MODE_MODEREG | DDR_MODE_BLEN_4) << | |
397 | SDRAM_MODE_SD_SHIFT) | | |
398 | ((DDR_MODE_CASLAT << SDRAM_MODE_SD_SHIFT) & | |
399 | MODE_CASLAT); | |
400 | SYNC; | |
401 | ||
402 | /* Set fast SDRAM refresh rate */ | |
403 | im->ddr.sdram_interval = | |
404 | (DDR_REFINT_166MHZ_7US << SDRAM_INTERVAL_REFINT_SHIFT) | | |
405 | (DDR_BSTOPRE << SDRAM_INTERVAL_BSTOPRE_SHIFT); | |
406 | SYNC; | |
10af6d53 WD |
407 | |
408 | /* Workaround for DDR6 Erratum | |
409 | * see MPC8349E Device Errata Rev.8, 2/2006 | |
410 | * This workaround influences the MPC internal "input enables" | |
411 | * dependent on CAS latency and MPC revision. According to errata | |
412 | * sheet the internal reserved registers for this workaround are | |
413 | * not available from revision 2.0 and up. | |
414 | */ | |
415 | ||
416 | /* Get REVID from register SPRIDR. Skip workaround if rev >= 2.0 | |
417 | * (0x200) | |
418 | */ | |
419 | if ((im->sysconf.spridr & SPRIDR_REVID) < 0x200) { | |
420 | ||
421 | /* There is a internal reserved register at IMMRBAR+0x2F00 | |
422 | * which has to be written with a certain value defined by | |
423 | * errata sheet. | |
424 | */ | |
966083e9 WD |
425 | u32 *reserved_p = (u32 *)((u8 *)im + 0x2f00); |
426 | ||
10af6d53 | 427 | #if defined(DDR_CASLAT_20) |
966083e9 | 428 | *reserved_p = 0x201c0000; |
10af6d53 | 429 | #else |
966083e9 | 430 | *reserved_p = 0x202c0000; |
10af6d53 WD |
431 | #endif |
432 | } | |
e6f2e902 | 433 | } |