// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2012 Michael Walle * Michael Walle * * Based on sheevaplug/sheevaplug.c by * Marvell Semiconductor */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lsxl.h" /* * Rescue mode * * Selected by holding the push button for 3 seconds, while powering on * the device. * * These linkstations don't have a (populated) serial port. There is no * way to access an (unmodified) board other than using the netconsole. If * you want to recover from a bad environment setting or an empty environment, * you can do this only with a working network connection. Therefore, a random * ethernet address is generated if none is set and a DHCP request is sent. * After a successful DHCP response is received, the network settings are * configured and the ncip is unset. Therefore, all netconsole packets are * broadcasted. * Additionally, the bootsource is set to 'rescue'. */ #ifndef CONFIG_ENV_OVERWRITE # error "You need to set CONFIG_ENV_OVERWRITE" #endif DECLARE_GLOBAL_DATA_PTR; int board_early_init_f(void) { /* * default gpio configuration * There are maximum 64 gpios controlled through 2 sets of registers * the below configuration configures mainly initial LED status */ mvebu_config_gpio(LSXL_OE_VAL_LOW, LSXL_OE_VAL_HIGH, LSXL_OE_LOW, LSXL_OE_HIGH); /* * Multi-Purpose Pins Functionality configuration * These strappings are taken from the original vendor uboot port. */ static const u32 kwmpp_config[] = { MPP0_SPI_SCn, MPP1_SPI_MOSI, MPP2_SPI_SCK, MPP3_SPI_MISO, MPP4_UART0_RXD, MPP5_UART0_TXD, MPP6_SYSRST_OUTn, MPP7_GPO, MPP8_GPIO, MPP9_GPIO, MPP10_GPO, /* HDD power */ MPP11_GPIO, /* USB Vbus enable */ MPP12_SD_CLK, MPP13_SD_CMD, MPP14_SD_D0, MPP15_SD_D1, MPP16_SD_D2, MPP17_SD_D3, MPP18_GPO, /* fan speed high */ MPP19_GPO, /* fan speed low */ MPP20_GE1_0, MPP21_GE1_1, MPP22_GE1_2, MPP23_GE1_3, MPP24_GE1_4, MPP25_GE1_5, MPP26_GE1_6, MPP27_GE1_7, MPP28_GPIO, MPP29_GPIO, MPP30_GE1_10, MPP31_GE1_11, MPP32_GE1_12, MPP33_GE1_13, MPP34_GPIO, MPP35_GPIO, MPP36_GPIO, /* function LED */ MPP37_GPIO, /* alarm LED */ MPP38_GPIO, /* info LED */ MPP39_GPIO, /* power LED */ MPP40_GPIO, /* fan alarm */ MPP41_GPIO, /* funtion button */ MPP42_GPIO, /* power switch */ MPP43_GPIO, /* power auto switch */ MPP44_GPIO, MPP45_GPIO, MPP46_GPIO, MPP47_GPIO, MPP48_GPIO, /* function red LED */ MPP49_GPIO, 0 }; kirkwood_mpp_conf(kwmpp_config, NULL); return 0; } #define LED_OFF 0 #define LED_ALARM_ON 1 #define LED_ALARM_BLINKING 2 #define LED_POWER_ON 3 #define LED_POWER_BLINKING 4 #define LED_INFO_ON 5 #define LED_INFO_BLINKING 6 static void __set_led(int blink_alarm, int blink_info, int blink_power, int value_alarm, int value_info, int value_power) { kw_gpio_set_blink(GPIO_ALARM_LED, blink_alarm); kw_gpio_set_blink(GPIO_INFO_LED, blink_info); kw_gpio_set_blink(GPIO_POWER_LED, blink_power); kw_gpio_set_value(GPIO_ALARM_LED, value_alarm); kw_gpio_set_value(GPIO_INFO_LED, value_info); kw_gpio_set_value(GPIO_POWER_LED, value_power); } static void set_led(int state) { switch (state) { case LED_OFF: __set_led(0, 0, 0, 1, 1, 1); break; case LED_ALARM_ON: __set_led(0, 0, 0, 0, 1, 1); break; case LED_ALARM_BLINKING: __set_led(1, 0, 0, 1, 1, 1); break; case LED_INFO_ON: __set_led(0, 0, 0, 1, 0, 1); break; case LED_INFO_BLINKING: __set_led(0, 1, 0, 1, 1, 1); break; case LED_POWER_ON: __set_led(0, 0, 0, 1, 1, 0); break; case LED_POWER_BLINKING: __set_led(0, 0, 1, 1, 1, 1); break; } } int board_init(void) { /* address of boot parameters */ gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100; set_led(LED_POWER_BLINKING); return 0; } #ifdef CONFIG_MISC_INIT_R static void check_power_switch(void) { if (kw_gpio_get_value(GPIO_POWER_SWITCH)) { /* turn off fan, HDD and USB power */ kw_gpio_set_value(GPIO_HDD_POWER, 0); kw_gpio_set_value(GPIO_USB_VBUS, 0); kw_gpio_set_value(GPIO_FAN_HIGH, 1); kw_gpio_set_value(GPIO_FAN_LOW, 1); set_led(LED_OFF); /* loop until released */ while (kw_gpio_get_value(GPIO_POWER_SWITCH)) ; /* turn power on again */ kw_gpio_set_value(GPIO_HDD_POWER, 1); kw_gpio_set_value(GPIO_USB_VBUS, 1); kw_gpio_set_value(GPIO_FAN_HIGH, 0); kw_gpio_set_value(GPIO_FAN_LOW, 0); set_led(LED_POWER_BLINKING); } } void check_enetaddr(void) { uchar enetaddr[6]; if (!eth_env_get_enetaddr("ethaddr", enetaddr)) { /* signal unset/invalid ethaddr to user */ set_led(LED_INFO_BLINKING); } } static void erase_environment(void) { struct spi_flash *flash; printf("Erasing environment..\n"); flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3); if (!flash) { printf("Erasing flash failed\n"); return; } spi_flash_erase(flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE); spi_flash_free(flash); do_reset(NULL, 0, 0, NULL); } static void rescue_mode(void) { printf("Entering rescue mode..\n"); env_set("bootsource", "rescue"); } static void check_push_button(void) { int i = 0; while (!kw_gpio_get_value(GPIO_FUNC_BUTTON)) { udelay(100000); i++; if (i == 10) set_led(LED_INFO_ON); if (i >= 100) { set_led(LED_INFO_BLINKING); break; } } if (i >= 100) erase_environment(); else if (i >= 10) rescue_mode(); } int misc_init_r(void) { check_power_switch(); check_enetaddr(); check_push_button(); return 0; } #endif #if CONFIG_IS_ENABLED(BOOTSTAGE) void show_boot_progress(int progress) { if (progress > 0) return; /* this is not an error, eg. bootp with autoload=no will trigger this */ if (progress == -BOOTSTAGE_ID_NET_LOADED) return; set_led(LED_ALARM_BLINKING); } #endif