mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-21 01:18:52 +09:00
![Simon Glass](/assets/img/avatar_default.png)
With driver model GPIOs must be requested before use. Make sure this is done correctly. (Note that the soft SPI part of universal is omitted, since this driver is about to be replaced with a driver-model-aware version) Signed-off-by: Simon Glass <sjg@chromium.org>
452 lines
8.5 KiB
C
452 lines
8.5 KiB
C
/*
|
|
* Copyright (C) 2013 Samsung Electronics
|
|
* Przemyslaw Marczak <p.marczak@samsung.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <lcd.h>
|
|
#include <libtizen.h>
|
|
#include <samsung/misc.h>
|
|
#include <errno.h>
|
|
#include <version.h>
|
|
#include <malloc.h>
|
|
#include <linux/sizes.h>
|
|
#include <asm/arch/cpu.h>
|
|
#include <asm/gpio.h>
|
|
#include <linux/input.h>
|
|
#include <power/pmic.h>
|
|
#include <mmc.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#ifdef CONFIG_SET_DFU_ALT_INFO
|
|
void set_dfu_alt_info(void)
|
|
{
|
|
size_t buf_size = CONFIG_SET_DFU_ALT_BUF_LEN;
|
|
ALLOC_CACHE_ALIGN_BUFFER(char, buf, buf_size);
|
|
char *alt_info = "Settings not found!";
|
|
char *status = "error!\n";
|
|
char *alt_setting;
|
|
char *alt_sep;
|
|
int offset = 0;
|
|
|
|
puts("DFU alt info setting: ");
|
|
|
|
alt_setting = get_dfu_alt_boot();
|
|
if (alt_setting) {
|
|
setenv("dfu_alt_boot", alt_setting);
|
|
offset = snprintf(buf, buf_size, "%s", alt_setting);
|
|
}
|
|
|
|
alt_setting = get_dfu_alt_system();
|
|
if (alt_setting) {
|
|
if (offset)
|
|
alt_sep = ";";
|
|
else
|
|
alt_sep = "";
|
|
|
|
offset += snprintf(buf + offset, buf_size - offset,
|
|
"%s%s", alt_sep, alt_setting);
|
|
}
|
|
|
|
if (offset) {
|
|
alt_info = buf;
|
|
status = "done\n";
|
|
}
|
|
|
|
setenv("dfu_alt_info", alt_info);
|
|
puts(status);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
|
|
void set_board_info(void)
|
|
{
|
|
char info[64];
|
|
|
|
snprintf(info, ARRAY_SIZE(info), "%u.%u", (s5p_cpu_rev & 0xf0) >> 4,
|
|
s5p_cpu_rev & 0xf);
|
|
setenv("soc_rev", info);
|
|
|
|
snprintf(info, ARRAY_SIZE(info), "%x", s5p_cpu_id);
|
|
setenv("soc_id", info);
|
|
|
|
#ifdef CONFIG_REVISION_TAG
|
|
snprintf(info, ARRAY_SIZE(info), "%x", get_board_rev());
|
|
setenv("board_rev", info);
|
|
#endif
|
|
#ifdef CONFIG_OF_LIBFDT
|
|
const char *bdtype = "";
|
|
const char *bdname = CONFIG_SYS_BOARD;
|
|
|
|
#ifdef CONFIG_BOARD_TYPES
|
|
bdtype = get_board_type();
|
|
sprintf(info, "%s%s", bdname, bdtype);
|
|
setenv("boardname", info);
|
|
#endif
|
|
snprintf(info, ARRAY_SIZE(info), "%s%x-%s%s.dtb",
|
|
CONFIG_SYS_SOC, s5p_cpu_id, bdname, bdtype);
|
|
setenv("fdtfile", info);
|
|
#endif
|
|
}
|
|
#endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */
|
|
|
|
#ifdef CONFIG_LCD_MENU
|
|
static int power_key_pressed(u32 reg)
|
|
{
|
|
struct pmic *pmic;
|
|
u32 status;
|
|
u32 mask;
|
|
|
|
pmic = pmic_get(KEY_PWR_PMIC_NAME);
|
|
if (!pmic) {
|
|
printf("%s: Not found\n", KEY_PWR_PMIC_NAME);
|
|
return 0;
|
|
}
|
|
|
|
if (pmic_probe(pmic))
|
|
return 0;
|
|
|
|
if (reg == KEY_PWR_STATUS_REG)
|
|
mask = KEY_PWR_STATUS_MASK;
|
|
else
|
|
mask = KEY_PWR_INTERRUPT_MASK;
|
|
|
|
if (pmic_reg_read(pmic, reg, &status))
|
|
return 0;
|
|
|
|
return !!(status & mask);
|
|
}
|
|
|
|
static int key_pressed(int key)
|
|
{
|
|
int value;
|
|
|
|
switch (key) {
|
|
case KEY_POWER:
|
|
value = power_key_pressed(KEY_PWR_INTERRUPT_REG);
|
|
break;
|
|
case KEY_VOLUMEUP:
|
|
value = !gpio_get_value(KEY_VOL_UP_GPIO);
|
|
break;
|
|
case KEY_VOLUMEDOWN:
|
|
value = !gpio_get_value(KEY_VOL_DOWN_GPIO);
|
|
break;
|
|
default:
|
|
value = 0;
|
|
break;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static int check_keys(void)
|
|
{
|
|
int keys = 0;
|
|
|
|
if (key_pressed(KEY_POWER))
|
|
keys += KEY_POWER;
|
|
if (key_pressed(KEY_VOLUMEUP))
|
|
keys += KEY_VOLUMEUP;
|
|
if (key_pressed(KEY_VOLUMEDOWN))
|
|
keys += KEY_VOLUMEDOWN;
|
|
|
|
return keys;
|
|
}
|
|
|
|
/*
|
|
* 0 BOOT_MODE_INFO
|
|
* 1 BOOT_MODE_THOR
|
|
* 2 BOOT_MODE_UMS
|
|
* 3 BOOT_MODE_DFU
|
|
* 4 BOOT_MODE_EXIT
|
|
*/
|
|
static char *
|
|
mode_name[BOOT_MODE_EXIT + 1][2] = {
|
|
{"DEVICE", ""},
|
|
{"THOR", "thor"},
|
|
{"UMS", "ums"},
|
|
{"DFU", "dfu"},
|
|
{"GPT", "gpt"},
|
|
{"ENV", "env"},
|
|
{"EXIT", ""},
|
|
};
|
|
|
|
static char *
|
|
mode_info[BOOT_MODE_EXIT + 1] = {
|
|
"info",
|
|
"downloader",
|
|
"mass storage",
|
|
"firmware update",
|
|
"restore",
|
|
"default",
|
|
"and run normal boot"
|
|
};
|
|
|
|
static char *
|
|
mode_cmd[BOOT_MODE_EXIT + 1] = {
|
|
"",
|
|
"thor 0 mmc 0",
|
|
"ums 0 mmc 0",
|
|
"dfu 0 mmc 0",
|
|
"gpt write mmc 0 $partitions",
|
|
"env default -a; saveenv",
|
|
"",
|
|
};
|
|
|
|
static void display_board_info(void)
|
|
{
|
|
#ifdef CONFIG_GENERIC_MMC
|
|
struct mmc *mmc = find_mmc_device(0);
|
|
#endif
|
|
vidinfo_t *vid = &panel_info;
|
|
|
|
lcd_position_cursor(4, 4);
|
|
|
|
lcd_printf("%s\n\t", U_BOOT_VERSION);
|
|
lcd_puts("\n\t\tBoard Info:\n");
|
|
#ifdef CONFIG_SYS_BOARD
|
|
lcd_printf("\tBoard name: %s\n", CONFIG_SYS_BOARD);
|
|
#endif
|
|
#ifdef CONFIG_REVISION_TAG
|
|
lcd_printf("\tBoard rev: %u\n", get_board_rev());
|
|
#endif
|
|
lcd_printf("\tDRAM banks: %u\n", CONFIG_NR_DRAM_BANKS);
|
|
lcd_printf("\tDRAM size: %u MB\n", gd->ram_size / SZ_1M);
|
|
|
|
#ifdef CONFIG_GENERIC_MMC
|
|
if (mmc) {
|
|
if (!mmc->capacity)
|
|
mmc_init(mmc);
|
|
|
|
lcd_printf("\teMMC size: %llu MB\n", mmc->capacity / SZ_1M);
|
|
}
|
|
#endif
|
|
if (vid)
|
|
lcd_printf("\tDisplay resolution: %u x % u\n",
|
|
vid->vl_col, vid->vl_row);
|
|
|
|
lcd_printf("\tDisplay BPP: %u\n", 1 << vid->vl_bpix);
|
|
}
|
|
|
|
static int mode_leave_menu(int mode)
|
|
{
|
|
char *exit_option;
|
|
char *exit_reset = "reset";
|
|
char *exit_back = "back";
|
|
cmd_tbl_t *cmd;
|
|
int cmd_result;
|
|
int leave;
|
|
|
|
lcd_clear();
|
|
|
|
switch (mode) {
|
|
case BOOT_MODE_EXIT:
|
|
return 1;
|
|
case BOOT_MODE_INFO:
|
|
display_board_info();
|
|
exit_option = exit_back;
|
|
leave = 0;
|
|
break;
|
|
default:
|
|
cmd = find_cmd(mode_name[mode][1]);
|
|
if (cmd) {
|
|
printf("Enter: %s %s\n", mode_name[mode][0],
|
|
mode_info[mode]);
|
|
lcd_printf("\n\n\t%s %s\n", mode_name[mode][0],
|
|
mode_info[mode]);
|
|
lcd_puts("\n\tDo not turn off device before finish!\n");
|
|
|
|
cmd_result = run_command(mode_cmd[mode], 0);
|
|
|
|
if (cmd_result == CMD_RET_SUCCESS) {
|
|
printf("Command finished\n");
|
|
lcd_clear();
|
|
lcd_printf("\n\n\t%s finished\n",
|
|
mode_name[mode][0]);
|
|
|
|
exit_option = exit_reset;
|
|
leave = 1;
|
|
} else {
|
|
printf("Command error\n");
|
|
lcd_clear();
|
|
lcd_printf("\n\n\t%s command error\n",
|
|
mode_name[mode][0]);
|
|
|
|
exit_option = exit_back;
|
|
leave = 0;
|
|
}
|
|
} else {
|
|
lcd_puts("\n\n\tThis mode is not supported.\n");
|
|
exit_option = exit_back;
|
|
leave = 0;
|
|
}
|
|
}
|
|
|
|
lcd_printf("\n\n\tPress POWER KEY to %s\n", exit_option);
|
|
|
|
/* Clear PWR button Rising edge interrupt status flag */
|
|
power_key_pressed(KEY_PWR_INTERRUPT_REG);
|
|
|
|
/* Wait for PWR key */
|
|
while (!key_pressed(KEY_POWER))
|
|
mdelay(1);
|
|
|
|
lcd_clear();
|
|
return leave;
|
|
}
|
|
|
|
static void display_download_menu(int mode)
|
|
{
|
|
char *selection[BOOT_MODE_EXIT + 1];
|
|
int i;
|
|
|
|
for (i = 0; i <= BOOT_MODE_EXIT; i++)
|
|
selection[i] = "[ ]";
|
|
|
|
selection[mode] = "[=>]";
|
|
|
|
lcd_clear();
|
|
lcd_printf("\n\n\t\tDownload Mode Menu\n\n");
|
|
|
|
for (i = 0; i <= BOOT_MODE_EXIT; i++)
|
|
lcd_printf("\t%s %s - %s\n\n", selection[i],
|
|
mode_name[i][0],
|
|
mode_info[i]);
|
|
}
|
|
|
|
static void download_menu(void)
|
|
{
|
|
int mode = 0;
|
|
int last_mode = 0;
|
|
int run;
|
|
int key = 0;
|
|
int timeout = 15; /* sec */
|
|
int i;
|
|
|
|
display_download_menu(mode);
|
|
|
|
lcd_puts("\n");
|
|
|
|
/* Start count if no key is pressed */
|
|
while (check_keys())
|
|
continue;
|
|
|
|
while (timeout--) {
|
|
lcd_printf("\r\tNormal boot will start in: %2.d seconds.",
|
|
timeout);
|
|
|
|
/* about 1000 ms in for loop */
|
|
for (i = 0; i < 10; i++) {
|
|
mdelay(100);
|
|
key = check_keys();
|
|
if (key)
|
|
break;
|
|
}
|
|
if (key)
|
|
break;
|
|
}
|
|
|
|
if (!key) {
|
|
lcd_clear();
|
|
return;
|
|
}
|
|
|
|
while (1) {
|
|
run = 0;
|
|
|
|
if (mode != last_mode)
|
|
display_download_menu(mode);
|
|
|
|
last_mode = mode;
|
|
mdelay(200);
|
|
|
|
key = check_keys();
|
|
switch (key) {
|
|
case KEY_POWER:
|
|
run = 1;
|
|
break;
|
|
case KEY_VOLUMEUP:
|
|
if (mode > 0)
|
|
mode--;
|
|
break;
|
|
case KEY_VOLUMEDOWN:
|
|
if (mode < BOOT_MODE_EXIT)
|
|
mode++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (run) {
|
|
if (mode_leave_menu(mode))
|
|
run_command("reset", 0);
|
|
|
|
display_download_menu(mode);
|
|
}
|
|
}
|
|
|
|
lcd_clear();
|
|
}
|
|
|
|
void check_boot_mode(void)
|
|
{
|
|
int pwr_key;
|
|
|
|
pwr_key = power_key_pressed(KEY_PWR_STATUS_REG);
|
|
if (!pwr_key)
|
|
return;
|
|
|
|
/* Clear PWR button Rising edge interrupt status flag */
|
|
power_key_pressed(KEY_PWR_INTERRUPT_REG);
|
|
|
|
if (key_pressed(KEY_VOLUMEUP))
|
|
download_menu();
|
|
else if (key_pressed(KEY_VOLUMEDOWN))
|
|
mode_leave_menu(BOOT_MODE_THOR);
|
|
}
|
|
|
|
void keys_init(void)
|
|
{
|
|
/* Set direction to input */
|
|
gpio_request(KEY_VOL_UP_GPIO, "volume-up");
|
|
gpio_request(KEY_VOL_DOWN_GPIO, "volume-down");
|
|
gpio_direction_input(KEY_VOL_UP_GPIO);
|
|
gpio_direction_input(KEY_VOL_DOWN_GPIO);
|
|
}
|
|
#endif /* CONFIG_LCD_MENU */
|
|
|
|
#ifdef CONFIG_CMD_BMP
|
|
void draw_logo(void)
|
|
{
|
|
int x, y;
|
|
ulong addr;
|
|
|
|
addr = panel_info.logo_addr;
|
|
if (!addr) {
|
|
error("There is no logo data.");
|
|
return;
|
|
}
|
|
|
|
if (panel_info.vl_width >= panel_info.logo_width) {
|
|
x = ((panel_info.vl_width - panel_info.logo_width) >> 1);
|
|
x += panel_info.logo_x_offset; /* For X center align */
|
|
} else {
|
|
x = 0;
|
|
printf("Warning: image width is bigger than display width\n");
|
|
}
|
|
|
|
if (panel_info.vl_height >= panel_info.logo_height) {
|
|
y = ((panel_info.vl_height - panel_info.logo_height) >> 1);
|
|
y += panel_info.logo_y_offset; /* For Y center align */
|
|
} else {
|
|
y = 0;
|
|
printf("Warning: image height is bigger than display height\n");
|
|
}
|
|
|
|
bmp_display(addr, x, y);
|
|
}
|
|
#endif /* CONFIG_CMD_BMP */
|