1f214a20eSMichael Walle /*
2f214a20eSMichael Walle * Copyright (c) 2012 Michael Walle
3f214a20eSMichael Walle * Michael Walle <michael@walle.cc>
4f214a20eSMichael Walle *
5f214a20eSMichael Walle * Based on sheevaplug/sheevaplug.c by
6f214a20eSMichael Walle * Marvell Semiconductor <www.marvell.com>
7f214a20eSMichael Walle *
81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
9f214a20eSMichael Walle */
10f214a20eSMichael Walle
11f214a20eSMichael Walle #include <common.h>
12f214a20eSMichael Walle #include <net.h>
13f214a20eSMichael Walle #include <malloc.h>
14f214a20eSMichael Walle #include <netdev.h>
15f214a20eSMichael Walle #include <miiphy.h>
16ff0960f9SSimon Glass #include <spi.h>
17ff0960f9SSimon Glass #include <spi_flash.h>
183dc23f78SStefan Roese #include <asm/arch/soc.h>
19f214a20eSMichael Walle #include <asm/arch/cpu.h>
20f214a20eSMichael Walle #include <asm/arch/mpp.h>
21f214a20eSMichael Walle #include <asm/arch/gpio.h>
22f214a20eSMichael Walle
23f214a20eSMichael Walle #include "lsxl.h"
24f214a20eSMichael Walle
25f214a20eSMichael Walle /*
26f214a20eSMichael Walle * Rescue mode
27f214a20eSMichael Walle *
28f214a20eSMichael Walle * Selected by holding the push button for 3 seconds, while powering on
29f214a20eSMichael Walle * the device.
30f214a20eSMichael Walle *
31f214a20eSMichael Walle * These linkstations don't have a (populated) serial port. There is no
32f214a20eSMichael Walle * way to access an (unmodified) board other than using the netconsole. If
33f214a20eSMichael Walle * you want to recover from a bad environment setting or an empty environment,
34f214a20eSMichael Walle * you can do this only with a working network connection. Therefore, a random
35f214a20eSMichael Walle * ethernet address is generated if none is set and a DHCP request is sent.
36f214a20eSMichael Walle * After a successful DHCP response is received, the network settings are
3723c9946aSMichael Walle * configured and the ncip is unset. Therefore, all netconsole packets are
3823c9946aSMichael Walle * broadcasted.
39f214a20eSMichael Walle * Additionally, the bootsource is set to 'rescue'.
40f214a20eSMichael Walle */
41f214a20eSMichael Walle
42f214a20eSMichael Walle #ifndef CONFIG_ENV_OVERWRITE
43f214a20eSMichael Walle # error "You need to set CONFIG_ENV_OVERWRITE"
44f214a20eSMichael Walle #endif
45f214a20eSMichael Walle
46f214a20eSMichael Walle DECLARE_GLOBAL_DATA_PTR;
47f214a20eSMichael Walle
board_early_init_f(void)48f214a20eSMichael Walle int board_early_init_f(void)
49f214a20eSMichael Walle {
50f214a20eSMichael Walle /*
51f214a20eSMichael Walle * default gpio configuration
52f214a20eSMichael Walle * There are maximum 64 gpios controlled through 2 sets of registers
53f214a20eSMichael Walle * the below configuration configures mainly initial LED status
54f214a20eSMichael Walle */
55d5c5132fSStefan Roese mvebu_config_gpio(LSXL_OE_VAL_LOW,
56f214a20eSMichael Walle LSXL_OE_VAL_HIGH,
57f214a20eSMichael Walle LSXL_OE_LOW, LSXL_OE_HIGH);
58f214a20eSMichael Walle
59f214a20eSMichael Walle /*
60f214a20eSMichael Walle * Multi-Purpose Pins Functionality configuration
61f214a20eSMichael Walle * These strappings are taken from the original vendor uboot port.
62f214a20eSMichael Walle */
639d86f0c3SAlbert ARIBAUD static const u32 kwmpp_config[] = {
64f214a20eSMichael Walle MPP0_SPI_SCn,
65f214a20eSMichael Walle MPP1_SPI_MOSI,
66f214a20eSMichael Walle MPP2_SPI_SCK,
67f214a20eSMichael Walle MPP3_SPI_MISO,
68f214a20eSMichael Walle MPP4_UART0_RXD,
69f214a20eSMichael Walle MPP5_UART0_TXD,
70f214a20eSMichael Walle MPP6_SYSRST_OUTn,
71f214a20eSMichael Walle MPP7_GPO,
72f214a20eSMichael Walle MPP8_GPIO,
73f214a20eSMichael Walle MPP9_GPIO,
74f214a20eSMichael Walle MPP10_GPO, /* HDD power */
75f214a20eSMichael Walle MPP11_GPIO, /* USB Vbus enable */
76f214a20eSMichael Walle MPP12_SD_CLK,
77f214a20eSMichael Walle MPP13_SD_CMD,
78f214a20eSMichael Walle MPP14_SD_D0,
79f214a20eSMichael Walle MPP15_SD_D1,
80f214a20eSMichael Walle MPP16_SD_D2,
81f214a20eSMichael Walle MPP17_SD_D3,
82f214a20eSMichael Walle MPP18_GPO, /* fan speed high */
83f214a20eSMichael Walle MPP19_GPO, /* fan speed low */
84f214a20eSMichael Walle MPP20_GE1_0,
85f214a20eSMichael Walle MPP21_GE1_1,
86f214a20eSMichael Walle MPP22_GE1_2,
87f214a20eSMichael Walle MPP23_GE1_3,
88f214a20eSMichael Walle MPP24_GE1_4,
89f214a20eSMichael Walle MPP25_GE1_5,
90f214a20eSMichael Walle MPP26_GE1_6,
91f214a20eSMichael Walle MPP27_GE1_7,
92f214a20eSMichael Walle MPP28_GPIO,
93f214a20eSMichael Walle MPP29_GPIO,
94f214a20eSMichael Walle MPP30_GE1_10,
95f214a20eSMichael Walle MPP31_GE1_11,
96f214a20eSMichael Walle MPP32_GE1_12,
97f214a20eSMichael Walle MPP33_GE1_13,
98f214a20eSMichael Walle MPP34_GPIO,
99f214a20eSMichael Walle MPP35_GPIO,
100f214a20eSMichael Walle MPP36_GPIO, /* function LED */
101f214a20eSMichael Walle MPP37_GPIO, /* alarm LED */
102f214a20eSMichael Walle MPP38_GPIO, /* info LED */
103f214a20eSMichael Walle MPP39_GPIO, /* power LED */
104f214a20eSMichael Walle MPP40_GPIO, /* fan alarm */
105f214a20eSMichael Walle MPP41_GPIO, /* funtion button */
106f214a20eSMichael Walle MPP42_GPIO, /* power switch */
107f214a20eSMichael Walle MPP43_GPIO, /* power auto switch */
108f214a20eSMichael Walle MPP44_GPIO,
109f214a20eSMichael Walle MPP45_GPIO,
110f214a20eSMichael Walle MPP46_GPIO,
111f214a20eSMichael Walle MPP47_GPIO,
112f214a20eSMichael Walle MPP48_GPIO, /* function red LED */
113f214a20eSMichael Walle MPP49_GPIO,
114f214a20eSMichael Walle 0
115f214a20eSMichael Walle };
116f214a20eSMichael Walle
117f214a20eSMichael Walle kirkwood_mpp_conf(kwmpp_config, NULL);
118f214a20eSMichael Walle
119f214a20eSMichael Walle return 0;
120f214a20eSMichael Walle }
121f214a20eSMichael Walle
122f214a20eSMichael Walle #define LED_OFF 0
123f214a20eSMichael Walle #define LED_ALARM_ON 1
124f214a20eSMichael Walle #define LED_ALARM_BLINKING 2
125f214a20eSMichael Walle #define LED_POWER_ON 3
126f214a20eSMichael Walle #define LED_POWER_BLINKING 4
127f214a20eSMichael Walle #define LED_INFO_ON 5
128f214a20eSMichael Walle #define LED_INFO_BLINKING 6
129f214a20eSMichael Walle
__set_led(int blink_alarm,int blink_info,int blink_power,int value_alarm,int value_info,int value_power)130f214a20eSMichael Walle static void __set_led(int blink_alarm, int blink_info, int blink_power,
131f214a20eSMichael Walle int value_alarm, int value_info, int value_power)
132f214a20eSMichael Walle {
133f214a20eSMichael Walle kw_gpio_set_blink(GPIO_ALARM_LED, blink_alarm);
134f214a20eSMichael Walle kw_gpio_set_blink(GPIO_INFO_LED, blink_info);
135f214a20eSMichael Walle kw_gpio_set_blink(GPIO_POWER_LED, blink_power);
136f214a20eSMichael Walle kw_gpio_set_value(GPIO_ALARM_LED, value_alarm);
137f214a20eSMichael Walle kw_gpio_set_value(GPIO_INFO_LED, value_info);
138f214a20eSMichael Walle kw_gpio_set_value(GPIO_POWER_LED, value_power);
139f214a20eSMichael Walle }
140f214a20eSMichael Walle
set_led(int state)141f214a20eSMichael Walle static void set_led(int state)
142f214a20eSMichael Walle {
143f214a20eSMichael Walle switch (state) {
144f214a20eSMichael Walle case LED_OFF:
145a9f1a489SMichael Walle __set_led(0, 0, 0, 1, 1, 1);
146f214a20eSMichael Walle break;
147f214a20eSMichael Walle case LED_ALARM_ON:
148f214a20eSMichael Walle __set_led(0, 0, 0, 0, 1, 1);
149f214a20eSMichael Walle break;
150f214a20eSMichael Walle case LED_ALARM_BLINKING:
151f214a20eSMichael Walle __set_led(1, 0, 0, 1, 1, 1);
152f214a20eSMichael Walle break;
153f214a20eSMichael Walle case LED_INFO_ON:
154f214a20eSMichael Walle __set_led(0, 0, 0, 1, 0, 1);
155f214a20eSMichael Walle break;
156f214a20eSMichael Walle case LED_INFO_BLINKING:
157f214a20eSMichael Walle __set_led(0, 1, 0, 1, 1, 1);
158f214a20eSMichael Walle break;
159f214a20eSMichael Walle case LED_POWER_ON:
160f214a20eSMichael Walle __set_led(0, 0, 0, 1, 1, 0);
161f214a20eSMichael Walle break;
162f214a20eSMichael Walle case LED_POWER_BLINKING:
163f214a20eSMichael Walle __set_led(0, 0, 1, 1, 1, 1);
164f214a20eSMichael Walle break;
165f214a20eSMichael Walle }
166f214a20eSMichael Walle }
167f214a20eSMichael Walle
board_init(void)168f214a20eSMichael Walle int board_init(void)
169f214a20eSMichael Walle {
170f214a20eSMichael Walle /* address of boot parameters */
17196c5f081SStefan Roese gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
172f214a20eSMichael Walle
173f214a20eSMichael Walle set_led(LED_POWER_BLINKING);
174f214a20eSMichael Walle
175f214a20eSMichael Walle return 0;
176f214a20eSMichael Walle }
177f214a20eSMichael Walle
178f214a20eSMichael Walle #ifdef CONFIG_MISC_INIT_R
check_power_switch(void)179a9f1a489SMichael Walle static void check_power_switch(void)
180a9f1a489SMichael Walle {
181a9f1a489SMichael Walle if (kw_gpio_get_value(GPIO_POWER_SWITCH)) {
1829bd2317bSMichael Walle /* turn off fan, HDD and USB power */
183a9f1a489SMichael Walle kw_gpio_set_value(GPIO_HDD_POWER, 0);
184a9f1a489SMichael Walle kw_gpio_set_value(GPIO_USB_VBUS, 0);
1859bd2317bSMichael Walle kw_gpio_set_value(GPIO_FAN_HIGH, 1);
1869bd2317bSMichael Walle kw_gpio_set_value(GPIO_FAN_LOW, 1);
187a9f1a489SMichael Walle set_led(LED_OFF);
188a9f1a489SMichael Walle
189a9f1a489SMichael Walle /* loop until released */
190a9f1a489SMichael Walle while (kw_gpio_get_value(GPIO_POWER_SWITCH))
191a9f1a489SMichael Walle ;
192a9f1a489SMichael Walle
193a9f1a489SMichael Walle /* turn power on again */
194a9f1a489SMichael Walle kw_gpio_set_value(GPIO_HDD_POWER, 1);
195a9f1a489SMichael Walle kw_gpio_set_value(GPIO_USB_VBUS, 1);
1969bd2317bSMichael Walle kw_gpio_set_value(GPIO_FAN_HIGH, 0);
1979bd2317bSMichael Walle kw_gpio_set_value(GPIO_FAN_LOW, 0);
198a9f1a489SMichael Walle set_led(LED_POWER_BLINKING);
199a9f1a489SMichael Walle }
200a9f1a489SMichael Walle }
201a9f1a489SMichael Walle
check_enetaddr(void)202f214a20eSMichael Walle void check_enetaddr(void)
203f214a20eSMichael Walle {
204f214a20eSMichael Walle uchar enetaddr[6];
205f214a20eSMichael Walle
206*35affd7aSSimon Glass if (!eth_env_get_enetaddr("ethaddr", enetaddr)) {
207f214a20eSMichael Walle /* signal unset/invalid ethaddr to user */
208f214a20eSMichael Walle set_led(LED_INFO_BLINKING);
209f214a20eSMichael Walle }
210f214a20eSMichael Walle }
211f214a20eSMichael Walle
erase_environment(void)212f214a20eSMichael Walle static void erase_environment(void)
213f214a20eSMichael Walle {
214f214a20eSMichael Walle struct spi_flash *flash;
215f214a20eSMichael Walle
216f214a20eSMichael Walle printf("Erasing environment..\n");
217f214a20eSMichael Walle flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3);
218f214a20eSMichael Walle if (!flash) {
219f214a20eSMichael Walle printf("Erasing flash failed\n");
220f214a20eSMichael Walle return;
221f214a20eSMichael Walle }
222f214a20eSMichael Walle
223f214a20eSMichael Walle spi_flash_erase(flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE);
224f214a20eSMichael Walle spi_flash_free(flash);
225f214a20eSMichael Walle do_reset(NULL, 0, 0, NULL);
226f214a20eSMichael Walle }
227f214a20eSMichael Walle
rescue_mode(void)228f214a20eSMichael Walle static void rescue_mode(void)
229f214a20eSMichael Walle {
230f214a20eSMichael Walle printf("Entering rescue mode..\n");
231382bee57SSimon Glass env_set("bootsource", "rescue");
232f214a20eSMichael Walle }
233f214a20eSMichael Walle
check_push_button(void)234f214a20eSMichael Walle static void check_push_button(void)
235f214a20eSMichael Walle {
236f214a20eSMichael Walle int i = 0;
237f214a20eSMichael Walle
238f214a20eSMichael Walle while (!kw_gpio_get_value(GPIO_FUNC_BUTTON)) {
239f214a20eSMichael Walle udelay(100000);
240f214a20eSMichael Walle i++;
241f214a20eSMichael Walle
242f214a20eSMichael Walle if (i == 10)
243f214a20eSMichael Walle set_led(LED_INFO_ON);
244f214a20eSMichael Walle
245f214a20eSMichael Walle if (i >= 100) {
246f214a20eSMichael Walle set_led(LED_INFO_BLINKING);
247f214a20eSMichael Walle break;
248f214a20eSMichael Walle }
249f214a20eSMichael Walle }
250f214a20eSMichael Walle
251f214a20eSMichael Walle if (i >= 100)
252f214a20eSMichael Walle erase_environment();
253f214a20eSMichael Walle else if (i >= 10)
254f214a20eSMichael Walle rescue_mode();
255f214a20eSMichael Walle }
256f214a20eSMichael Walle
misc_init_r(void)257f214a20eSMichael Walle int misc_init_r(void)
258f214a20eSMichael Walle {
259a9f1a489SMichael Walle check_power_switch();
260f214a20eSMichael Walle check_enetaddr();
261f214a20eSMichael Walle check_push_button();
262f214a20eSMichael Walle
263f214a20eSMichael Walle return 0;
264f214a20eSMichael Walle }
265f214a20eSMichael Walle #endif
266f214a20eSMichael Walle
267f214a20eSMichael Walle #ifdef CONFIG_SHOW_BOOT_PROGRESS
show_boot_progress(int progress)268f214a20eSMichael Walle void show_boot_progress(int progress)
269f214a20eSMichael Walle {
270f214a20eSMichael Walle if (progress > 0)
271f214a20eSMichael Walle return;
272f214a20eSMichael Walle
273f214a20eSMichael Walle /* this is not an error, eg. bootp with autoload=no will trigger this */
274f214a20eSMichael Walle if (progress == -BOOTSTAGE_ID_NET_LOADED)
275f214a20eSMichael Walle return;
276f214a20eSMichael Walle
277f214a20eSMichael Walle set_led(LED_ALARM_BLINKING);
278f214a20eSMichael Walle }
279f214a20eSMichael Walle #endif
280