mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-04 10:30:32 +00:00
7c9bd92eea
Use the new mvebu GPIO driver and convert all the function calls to the former kirkwood GPIO driver. This means that we are now using the LED uclass and the regulator uclass. Unfortunately, the GPIO LED doesn't offer a blinking method. Thus we are now stuck with solid on and off states, which makes debugging a bit harder. Also, there is no GPIO fan driver for now. Signed-off-by: Michael Walle <michael@walle.cc> Reviewed-by: Stefan Roese <sr@denx.de>
316 lines
6.1 KiB
C
316 lines
6.1 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (c) 2012 Michael Walle
|
|
* Michael Walle <michael@walle.cc>
|
|
*
|
|
* Based on sheevaplug/sheevaplug.c by
|
|
* Marvell Semiconductor <www.marvell.com>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <bootstage.h>
|
|
#include <button.h>
|
|
#include <command.h>
|
|
#include <env.h>
|
|
#include <init.h>
|
|
#include <led.h>
|
|
#include <power/regulator.h>
|
|
#include <spi.h>
|
|
#include <spi_flash.h>
|
|
#include <asm/arch/cpu.h>
|
|
#include <asm/arch/mpp.h>
|
|
#include <asm/global_data.h>
|
|
#include <asm/io.h>
|
|
#include <linux/delay.h>
|
|
|
|
#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'.
|
|
*/
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
static bool force_rescue_mode;
|
|
|
|
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;
|
|
}
|
|
|
|
enum {
|
|
LSXL_LED_OFF,
|
|
LSXL_LED_ALARM,
|
|
LSXL_LED_POWER,
|
|
LSXL_LED_INFO,
|
|
};
|
|
|
|
static void __set_led(int alarm, int info, int power)
|
|
{
|
|
struct udevice *led;
|
|
int ret;
|
|
|
|
ret = led_get_by_label("lsxl:red:alarm", &led);
|
|
if (!ret)
|
|
led_set_state(led, alarm);
|
|
ret = led_get_by_label("lsxl:amber:info", &led);
|
|
if (!ret)
|
|
led_set_state(led, info);
|
|
ret = led_get_by_label("lsxl:blue:power", &led);
|
|
if (!ret)
|
|
led_set_state(led, power);
|
|
}
|
|
|
|
static void set_led(int state)
|
|
{
|
|
switch (state) {
|
|
case LSXL_LED_OFF:
|
|
__set_led(0, 0, 0);
|
|
break;
|
|
case LSXL_LED_ALARM:
|
|
__set_led(1, 0, 0);
|
|
break;
|
|
case LSXL_LED_INFO:
|
|
__set_led(0, 1, 0);
|
|
break;
|
|
case LSXL_LED_POWER:
|
|
__set_led(0, 0, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int board_init(void)
|
|
{
|
|
/* address of boot parameters */
|
|
gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
|
|
|
|
set_led(LSXL_LED_POWER);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void check_power_switch(void)
|
|
{
|
|
struct udevice *power_button, *hdd_power, *usb_power;
|
|
int ret;
|
|
|
|
ret = button_get_by_label("Power-on Switch", &power_button);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = regulator_get_by_platname("HDD Power", &hdd_power);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = regulator_get_by_platname("USB Power", &usb_power);
|
|
if (ret)
|
|
goto err;
|
|
|
|
if (button_get_state(power_button) == BUTTON_OFF) {
|
|
ret = regulator_set_enable(hdd_power, false);
|
|
if (ret)
|
|
goto err;
|
|
ret = regulator_set_enable(usb_power, false);
|
|
if (ret)
|
|
goto err;
|
|
/* TODO: fan off */
|
|
set_led(LSXL_LED_OFF);
|
|
|
|
/* loop until released */
|
|
while (button_get_state(power_button) == BUTTON_OFF)
|
|
;
|
|
|
|
/* turn power on again */
|
|
ret = regulator_set_enable(hdd_power, true);
|
|
if (ret)
|
|
goto err;
|
|
ret = regulator_set_enable(usb_power, true);
|
|
if (ret)
|
|
goto err;
|
|
/* TODO: fan on */
|
|
set_led(LSXL_LED_POWER);
|
|
};
|
|
|
|
return;
|
|
err:
|
|
printf("error in %s\n", __func__);
|
|
}
|
|
|
|
void check_enetaddr(void)
|
|
{
|
|
uchar enetaddr[6];
|
|
|
|
if (!eth_env_get_enetaddr("ethaddr", enetaddr)) {
|
|
/* signal unset/invalid ethaddr to user */
|
|
set_led(LSXL_LED_INFO);
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
struct udevice *func_button;
|
|
int i = 0;
|
|
|
|
int ret;
|
|
|
|
ret = button_get_by_label("Function Button", &func_button);
|
|
if (ret)
|
|
goto err;
|
|
|
|
while (button_get_state(func_button) == BUTTON_ON) {
|
|
udelay(100000);
|
|
i++;
|
|
|
|
if (i == 10)
|
|
set_led(LSXL_LED_INFO);
|
|
|
|
if (i >= 100) {
|
|
set_led(LSXL_LED_ALARM);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= 100)
|
|
erase_environment();
|
|
else if (i >= 10)
|
|
force_rescue_mode = true;
|
|
|
|
return;
|
|
err:
|
|
printf("error in %s\n", __func__);
|
|
}
|
|
|
|
int board_early_init_r(void)
|
|
{
|
|
check_push_button();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int misc_init_r(void)
|
|
{
|
|
check_power_switch();
|
|
check_enetaddr();
|
|
if (force_rescue_mode)
|
|
rescue_mode();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#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(LSXL_LED_ALARM);
|
|
}
|
|
#endif
|