]>
Commit | Line | Data |
---|---|---|
86b116b1 BS |
1 | /* |
2 | * (C) Copyright 2003-2007 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * (C) Copyright 2004 | |
6 | * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. | |
7 | * | |
8 | * (C) Copyright 2004-2005 | |
9 | * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de | |
10 | * | |
11 | * Adapted to U-Boot 1.2 by: | |
12 | * Bartlomiej Sieka <tur@semihalf.com>: | |
13 | * - HW ID readout from EEPROM | |
14 | * - module detection | |
15 | * Grzegorz Bernacki <gjb@semihalf.com>: | |
16 | * - run-time SDRAM controller configuration | |
17 | * - LIBFDT support | |
18 | * | |
3765b3e7 | 19 | * SPDX-License-Identifier: GPL-2.0+ |
86b116b1 BS |
20 | */ |
21 | ||
22 | #include <common.h> | |
23 | #include <mpc5xxx.h> | |
24 | #include <pci.h> | |
25 | #include <asm/processor.h> | |
26 | #include <i2c.h> | |
27 | #include <linux/ctype.h> | |
28 | ||
29 | #ifdef CONFIG_OF_LIBFDT | |
30 | #include <libfdt.h> | |
86b116b1 BS |
31 | #include <fdt_support.h> |
32 | #endif /* CONFIG_OF_LIBFDT */ | |
33 | ||
34 | ||
35 | #include "cm5200.h" | |
36 | #include "fwupdate.h" | |
37 | ||
38 | DECLARE_GLOBAL_DATA_PTR; | |
39 | ||
40 | static hw_id_t hw_id; | |
41 | ||
42 | ||
6d0f6bcf | 43 | #ifndef CONFIG_SYS_RAMBOOT |
86b116b1 BS |
44 | /* |
45 | * Helper function to initialize SDRAM controller. | |
46 | */ | |
47 | static void sdram_start(int hi_addr, mem_conf_t *mem_conf) | |
48 | { | |
49 | long hi_addr_bit = hi_addr ? 0x01000000 : 0; | |
50 | ||
51 | /* unlock mode register */ | |
52 | *(vu_long *)MPC5XXX_SDRAM_CTRL = mem_conf->control | 0x80000000 | | |
53 | hi_addr_bit; | |
54 | ||
55 | /* precharge all banks */ | |
56 | *(vu_long *)MPC5XXX_SDRAM_CTRL = mem_conf->control | 0x80000002 | | |
57 | hi_addr_bit; | |
58 | ||
59 | /* auto refresh */ | |
60 | *(vu_long *)MPC5XXX_SDRAM_CTRL = mem_conf->control | 0x80000004 | | |
61 | hi_addr_bit; | |
62 | ||
63 | /* auto refresh, second time */ | |
64 | *(vu_long *)MPC5XXX_SDRAM_CTRL = mem_conf->control | 0x80000004 | | |
65 | hi_addr_bit; | |
66 | ||
67 | /* set mode register */ | |
68 | *(vu_long *)MPC5XXX_SDRAM_MODE = mem_conf->mode; | |
69 | ||
70 | /* normal operation */ | |
71 | *(vu_long *)MPC5XXX_SDRAM_CTRL = mem_conf->control | hi_addr_bit; | |
72 | } | |
6d0f6bcf | 73 | #endif /* CONFIG_SYS_RAMBOOT */ |
86b116b1 BS |
74 | |
75 | ||
76 | /* | |
77 | * Retrieve memory configuration for a given module. board_type is the index | |
78 | * in hw_id_list[] corresponding to the module we are executing on; we return | |
79 | * SDRAM controller settings approprate for this module. | |
80 | */ | |
81 | static mem_conf_t* get_mem_config(int board_type) | |
82 | { | |
83 | switch(board_type){ | |
84 | case CM1_QA: | |
85 | return memory_config[0]; | |
86 | case CM11_QA: | |
87 | case CMU1_QA: | |
88 | return memory_config[1]; | |
89 | default: | |
90 | printf("ERROR: Unknown module, using a default SDRAM " | |
91 | "configuration - things may not work!!!.\n"); | |
92 | return memory_config[0]; | |
93 | } | |
94 | } | |
95 | ||
96 | ||
97 | /* | |
98 | * Initalize SDRAM - configure SDRAM controller, detect memory size. | |
99 | */ | |
f1683aa7 | 100 | int dram_init(void) |
86b116b1 BS |
101 | { |
102 | ulong dramsize = 0; | |
6d0f6bcf | 103 | #ifndef CONFIG_SYS_RAMBOOT |
86b116b1 BS |
104 | ulong test1, test2; |
105 | mem_conf_t *mem_conf; | |
106 | ||
52c41180 | 107 | mem_conf = get_mem_config(gd->board_type); |
be5d72d1 | 108 | |
86b116b1 BS |
109 | /* configure SDRAM start/end for detection */ |
110 | *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x0000001e; /* 2G at 0x0 */ | |
111 | ||
112 | /* setup config registers */ | |
113 | *(vu_long *)MPC5XXX_SDRAM_CONFIG1 = mem_conf->config1; | |
114 | *(vu_long *)MPC5XXX_SDRAM_CONFIG2 = mem_conf->config2; | |
115 | ||
116 | sdram_start(0, mem_conf); | |
6d0f6bcf | 117 | test1 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x80000000); |
86b116b1 | 118 | sdram_start(1, mem_conf); |
6d0f6bcf | 119 | test2 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x80000000); |
86b116b1 BS |
120 | if (test1 > test2) { |
121 | sdram_start(0, mem_conf); | |
122 | dramsize = test1; | |
123 | } else | |
124 | dramsize = test2; | |
125 | ||
126 | /* memory smaller than 1MB is impossible */ | |
127 | if (dramsize < (1 << 20)) | |
128 | dramsize = 0; | |
129 | ||
130 | /* set SDRAM CS0 size according to the amount of RAM found */ | |
131 | if (dramsize > 0) { | |
132 | *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x13 + | |
133 | __builtin_ffs(dramsize >> 20) - 1; | |
134 | } else | |
135 | *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0; /* disabled */ | |
6d0f6bcf | 136 | #else /* CONFIG_SYS_RAMBOOT */ |
86b116b1 BS |
137 | /* retrieve size of memory connected to SDRAM CS0 */ |
138 | dramsize = *(vu_long *)MPC5XXX_SDRAM_CS0CFG & 0xFF; | |
139 | if (dramsize >= 0x13) | |
140 | dramsize = (1 << (dramsize - 0x13)) << 20; | |
141 | else | |
142 | dramsize = 0; | |
6d0f6bcf | 143 | #endif /* !CONFIG_SYS_RAMBOOT */ |
86b116b1 BS |
144 | |
145 | /* | |
146 | * On MPC5200B we need to set the special configuration delay in the | |
147 | * DDR controller. Refer to chapter 8.7.5 SDelay--MBAR + 0x0190 of | |
148 | * the MPC5200B User's Manual. | |
149 | */ | |
150 | *(vu_long *)MPC5XXX_SDRAM_SDELAY = 0x04; | |
151 | __asm__ volatile ("sync"); | |
152 | ||
088454cd SG |
153 | gd->ram_size = dramsize; |
154 | ||
155 | return 0; | |
86b116b1 BS |
156 | } |
157 | ||
158 | ||
159 | /* | |
160 | * Read module hardware identification data from the I2C EEPROM. | |
161 | */ | |
162 | static void read_hw_id(hw_id_t hw_id) | |
163 | { | |
eb5ba3ae | 164 | printf("ERROR: can't read HW ID from EEPROM\n"); |
86b116b1 BS |
165 | } |
166 | ||
167 | ||
168 | /* | |
169 | * Identify module we are running on, set gd->board_type to the index in | |
170 | * hw_id_list[] corresponding to the module identifed, or to | |
171 | * CM5200_UNKNOWN_MODULE if we can't identify the module. | |
172 | */ | |
173 | static void identify_module(hw_id_t hw_id) | |
174 | { | |
175 | int i, j, element; | |
176 | char match; | |
177 | gd->board_type = CM5200_UNKNOWN_MODULE; | |
178 | for (i = 0; i < sizeof (hw_id_list) / sizeof (char **); ++i) { | |
179 | match = 1; | |
180 | for (j = 0; j < sizeof (hw_id_identify) / sizeof (int); ++j) { | |
181 | element = hw_id_identify[j]; | |
182 | if (strncmp(hw_id_list[i][element], | |
183 | &hw_id[element][0], | |
184 | hw_id_format[element].length) != 0) { | |
185 | match = 0; | |
186 | break; | |
187 | } | |
188 | } | |
189 | if (match) { | |
190 | gd->board_type = i; | |
191 | break; | |
192 | } | |
193 | } | |
194 | } | |
195 | ||
196 | ||
197 | /* | |
198 | * Compose string with module name. | |
199 | * buf is assumed to have enough space, and be null-terminated. | |
200 | */ | |
201 | static void compose_module_name(hw_id_t hw_id, char *buf) | |
202 | { | |
203 | char tmp[MODULE_NAME_MAXLEN]; | |
204 | strncat(buf, &hw_id[PCB_NAME][0], hw_id_format[PCB_NAME].length); | |
205 | strncat(buf, ".", 1); | |
206 | strncat(buf, &hw_id[FORM][0], hw_id_format[FORM].length); | |
207 | strncat(buf, &hw_id[VERSION][0], hw_id_format[VERSION].length); | |
208 | strncat(buf, " (", 2); | |
209 | strncat(buf, &hw_id[IDENTIFICATION_NUMBER][0], | |
210 | hw_id_format[IDENTIFICATION_NUMBER].length); | |
211 | sprintf(tmp, " / %u.%u)", | |
212 | hw_id[MAJOR_SW_VERSION][0], | |
213 | hw_id[MINOR_SW_VERSION][0]); | |
214 | strcat(buf, tmp); | |
215 | } | |
216 | ||
b7c7a260 | 217 | #if defined(CONFIG_SYS_I2C_SOFT) |
86b116b1 BS |
218 | /* |
219 | * Compose string with hostname. | |
220 | * buf is assumed to have enough space, and be null-terminated. | |
221 | */ | |
222 | static void compose_hostname(hw_id_t hw_id, char *buf) | |
223 | { | |
224 | char *p; | |
225 | strncat(buf, &hw_id[PCB_NAME][0], hw_id_format[PCB_NAME].length); | |
226 | strncat(buf, "_", 1); | |
227 | strncat(buf, &hw_id[FORM][0], hw_id_format[FORM].length); | |
228 | strncat(buf, &hw_id[VERSION][0], hw_id_format[VERSION].length); | |
229 | for (p = buf; *p; ++p) | |
230 | *p = tolower(*p); | |
231 | ||
232 | } | |
eb5ba3ae | 233 | #endif |
86b116b1 | 234 | |
7ffe3cd6 | 235 | #ifdef CONFIG_OF_BOARD_SETUP |
86b116b1 BS |
236 | /* |
237 | * Update 'model' and 'memory' properties in the blob according to the module | |
238 | * that we are running on. | |
239 | */ | |
240 | static void ft_blob_update(void *blob, bd_t *bd) | |
241 | { | |
242 | int len, ret, nodeoffset = 0; | |
243 | char module_name[MODULE_NAME_MAXLEN] = {0}; | |
86b116b1 BS |
244 | |
245 | compose_module_name(hw_id, module_name); | |
246 | len = strlen(module_name) + 1; | |
247 | ||
248 | ret = fdt_setprop(blob, nodeoffset, "model", module_name, len); | |
249 | if (ret < 0) | |
250 | printf("ft_blob_update(): cannot set /model property err:%s\n", | |
251 | fdt_strerror(ret)); | |
86b116b1 | 252 | } |
7ffe3cd6 | 253 | #endif /* CONFIG_OF_BOARD_SETUP */ |
86b116b1 BS |
254 | |
255 | ||
256 | /* | |
257 | * Read HW ID from I2C EEPROM and detect the modue we are running on. Note | |
258 | * that we need to use local variable for readout, because global data is not | |
259 | * writable yet (and we'll have to redo the readout later on). | |
260 | */ | |
261 | int checkboard(void) | |
262 | { | |
263 | hw_id_t hw_id_tmp; | |
264 | char module_name_tmp[MODULE_NAME_MAXLEN] = ""; | |
265 | ||
86b116b1 BS |
266 | read_hw_id(hw_id_tmp); |
267 | identify_module(hw_id_tmp); /* this sets gd->board_type */ | |
268 | compose_module_name(hw_id_tmp, module_name_tmp); | |
269 | ||
270 | if (gd->board_type != CM5200_UNKNOWN_MODULE) | |
271 | printf("Board: %s\n", module_name_tmp); | |
272 | else | |
273 | printf("Board: unrecognized cm5200 module (%s)\n", | |
274 | module_name_tmp); | |
be5d72d1 | 275 | |
86b116b1 BS |
276 | return 0; |
277 | } | |
278 | ||
279 | ||
280 | int board_early_init_r(void) | |
281 | { | |
282 | /* | |
283 | * Now, when we are in RAM, enable flash write access for detection | |
284 | * process. Note that CS_BOOT cannot be cleared when executing in | |
285 | * flash. | |
286 | */ | |
287 | *(vu_long *)MPC5XXX_BOOTCS_CFG &= ~0x1; /* clear RO */ | |
288 | ||
289 | /* Now that we can write to global data, read HW ID again. */ | |
290 | read_hw_id(hw_id); | |
291 | return 0; | |
292 | } | |
293 | ||
294 | ||
86b116b1 BS |
295 | #ifdef CONFIG_MISC_INIT_R |
296 | int misc_init_r(void) | |
297 | { | |
b7c7a260 | 298 | #if defined(CONFIG_SYS_I2C_SOFT) |
86b116b1 BS |
299 | uchar buf[6]; |
300 | char str[18]; | |
301 | char hostname[MODULE_NAME_MAXLEN]; | |
302 | ||
303 | /* Read ethaddr from EEPROM */ | |
6d0f6bcf | 304 | if (i2c_read(CONFIG_SYS_I2C_EEPROM, CONFIG_MAC_OFFSET, 2, buf, 6) == 0) { |
86b116b1 BS |
305 | sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", |
306 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); | |
307 | /* Check if MAC addr is owned by Schindler */ | |
308 | if (strstr(str, "00:06:C3") != str) | |
309 | printf(LOG_PREFIX "Warning - Illegal MAC address (%s)" | |
310 | " in EEPROM.\n", str); | |
311 | else { | |
312 | printf(LOG_PREFIX "Using MAC (%s) from I2C EEPROM\n", | |
313 | str); | |
314 | setenv("ethaddr", str); | |
315 | } | |
316 | } else { | |
317 | printf(LOG_PREFIX "Warning - Unable to read MAC from I2C" | |
6d0f6bcf | 318 | " device at address %02X:%04X\n", CONFIG_SYS_I2C_EEPROM, |
86b116b1 BS |
319 | CONFIG_MAC_OFFSET); |
320 | } | |
eb5ba3ae SG |
321 | hostname[0] = 0x00; |
322 | /* set the hostname appropriate to the module we're running on */ | |
323 | compose_hostname(hw_id, hostname); | |
324 | setenv("hostname", hostname); | |
325 | ||
b7c7a260 | 326 | #endif /* defined(CONFIG_SYS_I2C_SOFT) */ |
86b116b1 BS |
327 | if (!getenv("ethaddr")) |
328 | printf(LOG_PREFIX "MAC address not set, networking is not " | |
329 | "operational\n"); | |
330 | ||
86b116b1 BS |
331 | return 0; |
332 | } | |
333 | #endif /* CONFIG_MISC_INIT_R */ | |
334 | ||
335 | ||
336 | #ifdef CONFIG_LAST_STAGE_INIT | |
337 | int last_stage_init(void) | |
338 | { | |
339 | #ifdef CONFIG_USB_STORAGE | |
340 | cm5200_fwupdate(); | |
341 | #endif /* CONFIG_USB_STORAGE */ | |
342 | return 0; | |
343 | } | |
344 | #endif /* CONFIG_LAST_STAGE_INIT */ | |
345 | ||
346 | ||
7ffe3cd6 | 347 | #ifdef CONFIG_OF_BOARD_SETUP |
e895a4b0 | 348 | int ft_board_setup(void *blob, bd_t *bd) |
86b116b1 BS |
349 | { |
350 | ft_cpu_setup(blob, bd); | |
351 | ft_blob_update(blob, bd); | |
e895a4b0 SG |
352 | |
353 | return 0; | |
86b116b1 | 354 | } |
7ffe3cd6 | 355 | #endif /* CONFIG_OF_BOARD_SETUP */ |