]>
Commit | Line | Data |
---|---|---|
67fa8c25 HS |
1 | /* |
2 | * (C) Copyright 2009 | |
3 | * Marvell Semiconductor <www.marvell.com> | |
4 | * Prafulla Wadaskar <prafulla@marvell.com> | |
5 | * | |
6 | * (C) Copyright 2009 | |
7 | * Stefan Roese, DENX Software Engineering, sr@denx.de. | |
8 | * | |
9 | * (C) Copyright 2010 | |
10 | * Heiko Schocher, DENX Software Engineering, hs@denx.de. | |
11 | * | |
12 | * See file CREDITS for list of people who contributed to this | |
13 | * project. | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or | |
16 | * modify it under the terms of the GNU General Public License as | |
17 | * published by the Free Software Foundation; either version 2 of | |
18 | * the License, or (at your option) any later version. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | * GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |
28 | * MA 02110-1301 USA | |
29 | */ | |
30 | ||
31 | #include <common.h> | |
32 | #include <i2c.h> | |
33 | #include <nand.h> | |
34 | #include <netdev.h> | |
35 | #include <miiphy.h> | |
0c25defc | 36 | #include <spi.h> |
67fa8c25 | 37 | #include <asm/io.h> |
a7efd719 | 38 | #include <asm/arch/cpu.h> |
67fa8c25 HS |
39 | #include <asm/arch/kirkwood.h> |
40 | #include <asm/arch/mpp.h> | |
41 | ||
42 | #include "../common/common.h" | |
43 | ||
44 | DECLARE_GLOBAL_DATA_PTR; | |
45 | ||
8612b701 HB |
46 | /* |
47 | * BOCO FPGA definitions | |
48 | */ | |
49 | #define BOCO 0x10 | |
50 | #define REG_CTRL_H 0x02 | |
51 | #define MASK_WRL_UNITRUN 0x01 | |
52 | #define MASK_RBX_PGY_PRESENT 0x40 | |
53 | #define REG_IRQ_CIRQ2 0x2d | |
54 | #define MASK_RBI_DEFECT_16 0x01 | |
55 | ||
67fa8c25 HS |
56 | /* Multi-Purpose Pins Functionality configuration */ |
57 | u32 kwmpp_config[] = { | |
58 | MPP0_NF_IO2, | |
59 | MPP1_NF_IO3, | |
60 | MPP2_NF_IO4, | |
61 | MPP3_NF_IO5, | |
62 | MPP4_NF_IO6, | |
63 | MPP5_NF_IO7, | |
64 | MPP6_SYSRST_OUTn, | |
65 | MPP7_PEX_RST_OUTn, | |
66 | #if defined(CONFIG_SOFT_I2C) | |
67 | MPP8_GPIO, /* SDA */ | |
68 | MPP9_GPIO, /* SCL */ | |
69 | #endif | |
70 | #if defined(CONFIG_HARD_I2C) | |
71 | MPP8_TW_SDA, | |
72 | MPP9_TW_SCK, | |
73 | #endif | |
74 | MPP10_UART0_TXD, | |
75 | MPP11_UART0_RXD, | |
76 | MPP12_GPO, /* Reserved */ | |
77 | MPP13_UART1_TXD, | |
78 | MPP14_UART1_RXD, | |
79 | MPP15_GPIO, /* Not used */ | |
80 | MPP16_GPIO, /* Not used */ | |
81 | MPP17_GPIO, /* Reserved */ | |
82 | MPP18_NF_IO0, | |
83 | MPP19_NF_IO1, | |
84 | MPP20_GPIO, | |
85 | MPP21_GPIO, | |
86 | MPP22_GPIO, | |
87 | MPP23_GPIO, | |
88 | MPP24_GPIO, | |
89 | MPP25_GPIO, | |
90 | MPP26_GPIO, | |
91 | MPP27_GPIO, | |
92 | MPP28_GPIO, | |
93 | MPP29_GPIO, | |
94 | MPP30_GPIO, | |
95 | MPP31_GPIO, | |
96 | MPP32_GPIO, | |
97 | MPP33_GPIO, | |
98 | MPP34_GPIO, /* CDL1 (input) */ | |
99 | MPP35_GPIO, /* CDL2 (input) */ | |
100 | MPP36_GPIO, /* MAIN_IRQ (input) */ | |
101 | MPP37_GPIO, /* BOARD_LED */ | |
102 | MPP38_GPIO, /* Piggy3 LED[1] */ | |
103 | MPP39_GPIO, /* Piggy3 LED[2] */ | |
104 | MPP40_GPIO, /* Piggy3 LED[3] */ | |
105 | MPP41_GPIO, /* Piggy3 LED[4] */ | |
106 | MPP42_GPIO, /* Piggy3 LED[5] */ | |
107 | MPP43_GPIO, /* Piggy3 LED[6] */ | |
44097e26 | 108 | MPP44_GPIO, /* Piggy3 LED[7], BIST_EN_L */ |
67fa8c25 HS |
109 | MPP45_GPIO, /* Piggy3 LED[8] */ |
110 | MPP46_GPIO, /* Reserved */ | |
111 | MPP47_GPIO, /* Reserved */ | |
112 | MPP48_GPIO, /* Reserved */ | |
113 | MPP49_GPIO, /* SW_INTOUTn */ | |
114 | 0 | |
115 | }; | |
116 | ||
f945439a | 117 | #if defined(CONFIG_KM_MGCOGE3UN) |
8612b701 HB |
118 | /* |
119 | * Wait for startup OK from mgcoge3ne | |
120 | */ | |
121 | int startup_allowed(void) | |
122 | { | |
123 | unsigned char buf; | |
124 | ||
125 | /* | |
126 | * Read CIRQ16 bit (bit 0) | |
127 | */ | |
128 | if (i2c_read(BOCO, REG_IRQ_CIRQ2, 1, &buf, 1) != 0) | |
129 | printf("%s: Error reading Boco\n", __func__); | |
130 | else | |
131 | if ((buf & MASK_RBI_DEFECT_16) == MASK_RBI_DEFECT_16) | |
132 | return 1; | |
133 | return 0; | |
134 | } | |
01fa4e8c | 135 | #endif |
8612b701 | 136 | |
f945439a | 137 | #if (defined(CONFIG_KM_PIGGY4_88E6061)|defined(CONFIG_KM_PIGGY4_88E6352)) |
8612b701 | 138 | /* |
8170aefc HB |
139 | * All boards with PIGGY4 connected via a simple switch have ethernet always |
140 | * present. | |
8612b701 HB |
141 | */ |
142 | int ethernet_present(void) | |
143 | { | |
144 | return 1; | |
145 | } | |
146 | #else | |
67fa8c25 HS |
147 | int ethernet_present(void) |
148 | { | |
149 | uchar buf; | |
150 | int ret = 0; | |
151 | ||
8612b701 | 152 | if (i2c_read(BOCO, REG_CTRL_H, 1, &buf, 1) != 0) { |
b11f53f3 | 153 | printf("%s: Error reading Boco\n", __func__); |
67fa8c25 HS |
154 | return -1; |
155 | } | |
8612b701 | 156 | if ((buf & MASK_RBX_PGY_PRESENT) == MASK_RBX_PGY_PRESENT) |
67fa8c25 | 157 | ret = 1; |
b11f53f3 | 158 | |
67fa8c25 HS |
159 | return ret; |
160 | } | |
8612b701 | 161 | #endif |
67fa8c25 | 162 | |
731b9680 HS |
163 | int initialize_unit_leds(void) |
164 | { | |
165 | /* | |
8612b701 | 166 | * Init the unit LEDs per default they all are |
731b9680 | 167 | * ok apart from bootstat |
731b9680 | 168 | */ |
731b9680 HS |
169 | uchar buf; |
170 | ||
8612b701 | 171 | if (i2c_read(BOCO, REG_CTRL_H, 1, &buf, 1) != 0) { |
731b9680 HS |
172 | printf("%s: Error reading Boco\n", __func__); |
173 | return -1; | |
174 | } | |
8612b701 HB |
175 | buf |= MASK_WRL_UNITRUN; |
176 | if (i2c_write(BOCO, REG_CTRL_H, 1, &buf, 1) != 0) { | |
731b9680 HS |
177 | printf("%s: Error writing Boco\n", __func__); |
178 | return -1; | |
179 | } | |
180 | return 0; | |
181 | } | |
182 | ||
22c67d08 VL |
183 | #if defined(CONFIG_BOOTCOUNT_LIMIT) |
184 | void set_bootcount_addr(void) | |
185 | { | |
186 | uchar buf[32]; | |
187 | unsigned int bootcountaddr; | |
188 | bootcountaddr = gd->ram_size - BOOTCOUNT_ADDR; | |
189 | sprintf((char *)buf, "0x%x", bootcountaddr); | |
190 | setenv("bootcountaddr", (char *)buf); | |
191 | } | |
192 | #endif | |
193 | ||
67fa8c25 HS |
194 | int misc_init_r(void) |
195 | { | |
67fa8c25 HS |
196 | char *str; |
197 | int mach_type; | |
198 | ||
67fa8c25 HS |
199 | str = getenv("mach_type"); |
200 | if (str != NULL) { | |
201 | mach_type = simple_strtoul(str, NULL, 10); | |
202 | printf("Overwriting MACH_TYPE with %d!!!\n", mach_type); | |
203 | gd->bd->bi_arch_number = mach_type; | |
204 | } | |
f945439a | 205 | #if defined(CONFIG_KM_MGCOGE3UN) |
8612b701 HB |
206 | char *wait_for_ne; |
207 | wait_for_ne = getenv("waitforne"); | |
208 | if (wait_for_ne != NULL) { | |
209 | if (strcmp(wait_for_ne, "true") == 0) { | |
210 | int cnt = 0; | |
6264800e | 211 | int abort = 0; |
8612b701 HB |
212 | puts("NE go: "); |
213 | while (startup_allowed() == 0) { | |
6264800e HB |
214 | if (tstc()) { |
215 | (void) getc(); /* consume input */ | |
216 | abort = 1; | |
217 | break; | |
218 | } | |
8612b701 HB |
219 | udelay(200000); |
220 | cnt++; | |
221 | if (cnt == 5) | |
222 | puts("wait\b\b\b\b"); | |
223 | if (cnt == 10) { | |
224 | cnt = 0; | |
225 | puts(" \b\b\b\b"); | |
226 | } | |
227 | } | |
6264800e HB |
228 | if (abort == 1) |
229 | printf("\nAbort waiting for ne\n"); | |
230 | else | |
231 | puts("OK\n"); | |
8612b701 HB |
232 | } |
233 | } | |
234 | #endif | |
731b9680 HS |
235 | |
236 | initialize_unit_leds(); | |
22c67d08 VL |
237 | set_km_env(); |
238 | #if defined(CONFIG_BOOTCOUNT_LIMIT) | |
239 | set_bootcount_addr(); | |
240 | #endif | |
67fa8c25 HS |
241 | return 0; |
242 | } | |
243 | ||
6b0ccc3b | 244 | int board_early_init_f(void) |
67fa8c25 HS |
245 | { |
246 | u32 tmp; | |
247 | ||
84683638 | 248 | kirkwood_mpp_conf(kwmpp_config, NULL); |
67fa8c25 HS |
249 | |
250 | /* | |
251 | * The FLASH_GPIO_PIN switches between using a | |
252 | * NAND or a SPI FLASH. Set this pin on start | |
253 | * to NAND mode. | |
254 | */ | |
255 | tmp = readl(KW_GPIO0_BASE); | |
256 | writel(tmp | FLASH_GPIO_PIN , KW_GPIO0_BASE); | |
257 | tmp = readl(KW_GPIO0_BASE + 4); | |
258 | writel(tmp & (~FLASH_GPIO_PIN) , KW_GPIO0_BASE + 4); | |
67fa8c25 | 259 | |
67fa8c25 HS |
260 | #if defined(CONFIG_SOFT_I2C) |
261 | /* init the GPIO for I2C Bitbang driver */ | |
44097e26 HS |
262 | kw_gpio_set_valid(KM_KIRKWOOD_SDA_PIN, 1); |
263 | kw_gpio_set_valid(KM_KIRKWOOD_SCL_PIN, 1); | |
264 | kw_gpio_direction_output(KM_KIRKWOOD_SDA_PIN, 0); | |
265 | kw_gpio_direction_output(KM_KIRKWOOD_SCL_PIN, 0); | |
67fa8c25 HS |
266 | #endif |
267 | #if defined(CONFIG_SYS_EEPROM_WREN) | |
44097e26 HS |
268 | kw_gpio_set_valid(KM_KIRKWOOD_ENV_WP, 38); |
269 | kw_gpio_direction_output(KM_KIRKWOOD_ENV_WP, 1); | |
f0d64257 | 270 | #endif |
6b0ccc3b HS |
271 | return 0; |
272 | } | |
273 | ||
274 | int board_init(void) | |
275 | { | |
6b0ccc3b HS |
276 | /* address of boot parameters */ |
277 | gd->bd->bi_boot_params = kw_sdram_bar(0) + 0x100; | |
278 | ||
b37f7724 VL |
279 | #if defined(CONFIG_KM_FPGA_CONFIG) |
280 | trigger_fpga_config(); | |
281 | #endif | |
282 | ||
283 | return 0; | |
284 | } | |
285 | ||
286 | int board_late_init(void) | |
287 | { | |
288 | #if defined(CONFIG_KM_FPGA_CONFIG) | |
289 | wait_for_fpga_config(); | |
290 | fpga_reset(); | |
291 | toggle_eeprom_spi_bus(); | |
292 | #endif | |
293 | ||
67fa8c25 HS |
294 | return 0; |
295 | } | |
296 | ||
0c25defc | 297 | int board_spi_claim_bus(struct spi_slave *slave) |
67fa8c25 | 298 | { |
0c25defc | 299 | kw_gpio_set_value(KM_FLASH_GPIO_PIN, 0); |
67fa8c25 HS |
300 | |
301 | return 0; | |
302 | } | |
303 | ||
0c25defc VL |
304 | void board_spi_release_bus(struct spi_slave *slave) |
305 | { | |
306 | kw_gpio_set_value(KM_FLASH_GPIO_PIN, 1); | |
307 | } | |
67fa8c25 | 308 | |
ab86f72c HS |
309 | int dram_init(void) |
310 | { | |
311 | /* dram_init must store complete ramsize in gd->ram_size */ | |
312 | /* Fix this */ | |
a55d23cc | 313 | gd->ram_size = get_ram_size((void *)kw_sdram_bar(0), |
ab86f72c | 314 | kw_sdram_bs(0)); |
67fa8c25 HS |
315 | return 0; |
316 | } | |
317 | ||
ab86f72c HS |
318 | void dram_init_banksize(void) |
319 | { | |
320 | int i; | |
321 | ||
322 | for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { | |
323 | gd->bd->bi_dram[i].start = kw_sdram_bar(i); | |
ab86f72c HS |
324 | gd->bd->bi_dram[i].size = get_ram_size((long *)kw_sdram_bar(i), |
325 | kw_sdram_bs(i)); | |
326 | } | |
327 | } | |
ab86f72c | 328 | |
6ef64861 | 329 | #if (defined(CONFIG_KM_PIGGY4_88E6061)) |
8f2827fc VL |
330 | |
331 | #define PHY_LED_SEL 0x18 | |
332 | #define PHY_LED0_LINK (0x5) | |
333 | #define PHY_LED1_ACT (0x8<<4) | |
334 | #define PHY_LED2_INT (0xe<<8) | |
335 | #define PHY_SPEC_CTRL 0x1c | |
336 | #define PHY_RGMII_CLK_STABLE (0x1<<10) | |
337 | #define PHY_CLSA (0x1<<1) | |
338 | ||
339 | /* Configure and enable MV88E3018 PHY */ | |
340 | void reset_phy(void) | |
341 | { | |
342 | char *name = "egiga0"; | |
343 | unsigned short reg; | |
344 | ||
345 | if (miiphy_set_current_dev(name)) | |
346 | return; | |
347 | ||
348 | /* RGMII clk transition on data stable */ | |
349 | if (miiphy_read(name, CONFIG_PHY_BASE_ADR, PHY_SPEC_CTRL, ®) != 0) | |
350 | printf("Error reading PHY spec ctrl reg\n"); | |
351 | if (miiphy_write(name, CONFIG_PHY_BASE_ADR, PHY_SPEC_CTRL, | |
352 | reg | PHY_RGMII_CLK_STABLE | PHY_CLSA) != 0) | |
353 | printf("Error writing PHY spec ctrl reg\n"); | |
354 | ||
355 | /* leds setup */ | |
356 | if (miiphy_write(name, CONFIG_PHY_BASE_ADR, PHY_LED_SEL, | |
357 | PHY_LED0_LINK | PHY_LED1_ACT | PHY_LED2_INT) != 0) | |
358 | printf("Error writing PHY LED reg\n"); | |
359 | ||
360 | /* reset the phy */ | |
361 | miiphy_reset(name, CONFIG_PHY_BASE_ADR); | |
362 | } | |
363 | #else | |
364 | /* Configure and enable MV88E1118 PHY on the piggy*/ | |
67fa8c25 HS |
365 | void reset_phy(void) |
366 | { | |
367 | char *name = "egiga0"; | |
368 | ||
369 | if (miiphy_set_current_dev(name)) | |
370 | return; | |
371 | ||
372 | /* reset the phy */ | |
373 | miiphy_reset(name, CONFIG_PHY_BASE_ADR); | |
374 | } | |
8f2827fc VL |
375 | #endif |
376 | ||
67fa8c25 HS |
377 | |
378 | #if defined(CONFIG_HUSH_INIT_VAR) | |
b11f53f3 | 379 | int hush_init_var(void) |
67fa8c25 | 380 | { |
b11f53f3 | 381 | ivm_read_eeprom(); |
67fa8c25 HS |
382 | return 0; |
383 | } | |
384 | #endif | |
385 | ||
386 | #if defined(CONFIG_BOOTCOUNT_LIMIT) | |
37605c46 HB |
387 | const ulong patterns[] = { 0x00000000, |
388 | 0xFFFFFFFF, | |
389 | 0xFF00FF00, | |
390 | 0x0F0F0F0F, | |
391 | 0xF0F0F0F0}; | |
b7326323 | 392 | const ulong NBR_OF_PATTERNS = ARRAY_SIZE(patterns); |
37605c46 HB |
393 | const ulong OFFS_PATTERN = 3; |
394 | const ulong REPEAT_PATTERN = 1000; | |
395 | ||
b11f53f3 | 396 | void bootcount_store(ulong a) |
67fa8c25 | 397 | { |
6a23f311 HB |
398 | ulong *save_addr; |
399 | ulong size = 0; | |
67fa8c25 | 400 | int i; |
6a23f311 HB |
401 | |
402 | for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) | |
67fa8c25 | 403 | size += gd->bd->bi_dram[i].size; |
6a23f311 | 404 | save_addr = (ulong *)(size - BOOTCOUNT_ADDR); |
67fa8c25 HS |
405 | writel(a, save_addr); |
406 | writel(BOOTCOUNT_MAGIC, &save_addr[1]); | |
37605c46 HB |
407 | |
408 | for (i = 0; i < REPEAT_PATTERN; i++) | |
409 | writel(patterns[i % NBR_OF_PATTERNS], | |
410 | &save_addr[i+OFFS_PATTERN]); | |
411 | ||
67fa8c25 HS |
412 | } |
413 | ||
b11f53f3 | 414 | ulong bootcount_load(void) |
67fa8c25 | 415 | { |
6a23f311 HB |
416 | ulong *save_addr; |
417 | ulong size = 0; | |
37605c46 HB |
418 | ulong counter = 0; |
419 | int i, tmp; | |
420 | ||
6a23f311 | 421 | for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) |
67fa8c25 | 422 | size += gd->bd->bi_dram[i].size; |
6a23f311 | 423 | save_addr = (ulong *)(size - BOOTCOUNT_ADDR); |
37605c46 HB |
424 | |
425 | counter = readl(&save_addr[0]); | |
426 | ||
427 | /* Is the counter reliable, check in the big pattern for bit errors */ | |
428 | for (i = 0; (i < REPEAT_PATTERN) && (counter != 0); i++) { | |
429 | tmp = readl(&save_addr[i+OFFS_PATTERN]); | |
430 | if (tmp != patterns[i % NBR_OF_PATTERNS]) | |
431 | counter = 0; | |
432 | } | |
433 | return counter; | |
67fa8c25 HS |
434 | } |
435 | #endif | |
436 | ||
437 | #if defined(CONFIG_SOFT_I2C) | |
b11f53f3 | 438 | void set_sda(int state) |
67fa8c25 HS |
439 | { |
440 | I2C_ACTIVE; | |
441 | I2C_SDA(state); | |
442 | } | |
443 | ||
b11f53f3 | 444 | void set_scl(int state) |
67fa8c25 HS |
445 | { |
446 | I2C_SCL(state); | |
447 | } | |
448 | ||
b11f53f3 | 449 | int get_sda(void) |
67fa8c25 HS |
450 | { |
451 | I2C_TRISTATE; | |
452 | return I2C_READ; | |
453 | } | |
454 | ||
b11f53f3 | 455 | int get_scl(void) |
67fa8c25 | 456 | { |
44097e26 | 457 | return kw_gpio_get_value(KM_KIRKWOOD_SCL_PIN) ? 1 : 0; |
67fa8c25 HS |
458 | } |
459 | #endif | |
460 | ||
9400f8fa VL |
461 | #if defined(CONFIG_POST) |
462 | ||
463 | #define KM_POST_EN_L 44 | |
464 | #define POST_WORD_OFF 8 | |
465 | ||
466 | int post_hotkeys_pressed(void) | |
467 | { | |
d9354530 HB |
468 | #if defined(CONFIG_KM_COGE5UN) |
469 | return kw_gpio_get_value(KM_POST_EN_L); | |
470 | #else | |
9400f8fa | 471 | return !kw_gpio_get_value(KM_POST_EN_L); |
d9354530 | 472 | #endif |
9400f8fa VL |
473 | } |
474 | ||
475 | ulong post_word_load(void) | |
476 | { | |
6a23f311 | 477 | void* addr = (void *) (gd->ram_size - BOOTCOUNT_ADDR + POST_WORD_OFF); |
9400f8fa VL |
478 | return in_le32(addr); |
479 | ||
480 | } | |
481 | void post_word_store(ulong value) | |
482 | { | |
6a23f311 | 483 | void* addr = (void *) (gd->ram_size - BOOTCOUNT_ADDR + POST_WORD_OFF); |
9400f8fa VL |
484 | out_le32(addr, value); |
485 | } | |
486 | ||
487 | int arch_memory_test_prepare(u32 *vstart, u32 *size, phys_addr_t *phys_offset) | |
488 | { | |
489 | *vstart = CONFIG_SYS_SDRAM_BASE; | |
490 | ||
491 | /* we go up to relocation plus a 1 MB margin */ | |
492 | *size = CONFIG_SYS_TEXT_BASE - (1<<20); | |
493 | ||
494 | return 0; | |
495 | } | |
496 | #endif | |
497 | ||
67fa8c25 | 498 | #if defined(CONFIG_SYS_EEPROM_WREN) |
b11f53f3 | 499 | int eeprom_write_enable(unsigned dev_addr, int state) |
67fa8c25 | 500 | { |
44097e26 | 501 | kw_gpio_set_value(KM_KIRKWOOD_ENV_WP, !state); |
67fa8c25 | 502 | |
44097e26 | 503 | return !kw_gpio_get_value(KM_KIRKWOOD_ENV_WP); |
67fa8c25 HS |
504 | } |
505 | #endif |