diff options
Diffstat (limited to 'arch/arm/mach-uniphier/boot-device/boot-device.c')
-rw-r--r-- | arch/arm/mach-uniphier/boot-device/boot-device.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/arch/arm/mach-uniphier/boot-device/boot-device.c b/arch/arm/mach-uniphier/boot-device/boot-device.c new file mode 100644 index 0000000..5ec0b5b --- /dev/null +++ b/arch/arm/mach-uniphier/boot-device/boot-device.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2015-2017 Socionext Inc. + * Author: Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <spl.h> +#include <linux/log2.h> + +#include "../init.h" +#include "../sbc/sbc-regs.h" +#include "../sg-regs.h" +#include "../soc-info.h" +#include "boot-device.h" + +struct uniphier_boot_device_info { + unsigned int soc_id; + unsigned int boot_device_sel_shift; + const struct uniphier_boot_device *boot_device_table; + const unsigned int *boot_device_count; + int (*boot_device_is_usb)(u32 pinmon); + unsigned int (*boot_device_fixup)(unsigned int mode); +}; + +static const struct uniphier_boot_device_info uniphier_boot_device_info[] = { +#if defined(CONFIG_ARCH_UNIPHIER_SLD3) + { + .soc_id = UNIPHIER_SLD3_ID, + .boot_device_sel_shift = 0, + .boot_device_table = uniphier_sld3_boot_device_table, + .boot_device_count = &uniphier_sld3_boot_device_count, + }, +#endif +#if defined(CONFIG_ARCH_UNIPHIER_LD4) + { + .soc_id = UNIPHIER_LD4_ID, + .boot_device_sel_shift = 1, + .boot_device_table = uniphier_ld4_boot_device_table, + .boot_device_count = &uniphier_ld4_boot_device_count, + }, +#endif +#if defined(CONFIG_ARCH_UNIPHIER_PRO4) + { + .soc_id = UNIPHIER_PRO4_ID, + .boot_device_sel_shift = 1, + .boot_device_table = uniphier_ld4_boot_device_table, + .boot_device_count = &uniphier_ld4_boot_device_count, + }, +#endif +#if defined(CONFIG_ARCH_UNIPHIER_SLD8) + { + .soc_id = UNIPHIER_SLD8_ID, + .boot_device_sel_shift = 1, + .boot_device_table = uniphier_ld4_boot_device_table, + .boot_device_count = &uniphier_ld4_boot_device_count, + }, +#endif +#if defined(CONFIG_ARCH_UNIPHIER_PRO5) + { + .soc_id = UNIPHIER_PRO5_ID, + .boot_device_sel_shift = 1, + .boot_device_table = uniphier_pro5_boot_device_table, + .boot_device_count = &uniphier_pro5_boot_device_count, + }, +#endif +#if defined(CONFIG_ARCH_UNIPHIER_PXS2) + { + .soc_id = UNIPHIER_PXS2_ID, + .boot_device_sel_shift = 1, + .boot_device_table = uniphier_pxs2_boot_device_table, + .boot_device_count = &uniphier_pxs2_boot_device_count, + .boot_device_is_usb = uniphier_pxs2_boot_device_is_usb, + .boot_device_fixup = uniphier_pxs2_boot_device_fixup, + }, +#endif +#if defined(CONFIG_ARCH_UNIPHIER_LD6B) + { + .soc_id = UNIPHIER_LD6B_ID, + .boot_device_sel_shift = 1, + .boot_device_table = uniphier_pxs2_boot_device_table, + .boot_device_count = &uniphier_pxs2_boot_device_count, + .boot_device_is_usb = uniphier_pxs2_boot_device_is_usb, + .boot_device_fixup = uniphier_pxs2_boot_device_fixup, + }, +#endif +#if defined(CONFIG_ARCH_UNIPHIER_LD11) + { + .soc_id = UNIPHIER_LD11_ID, + .boot_device_sel_shift = 1, + .boot_device_table = uniphier_ld11_boot_device_table, + .boot_device_count = &uniphier_ld11_boot_device_count, + .boot_device_is_usb = uniphier_ld11_boot_device_is_usb, + .boot_device_fixup = uniphier_ld11_boot_device_fixup, + }, +#endif +#if defined(CONFIG_ARCH_UNIPHIER_LD20) + { + .soc_id = UNIPHIER_LD20_ID, + .boot_device_sel_shift = 1, + .boot_device_table = uniphier_ld11_boot_device_table, + .boot_device_count = &uniphier_ld11_boot_device_count, + .boot_device_is_usb = uniphier_ld20_boot_device_is_usb, + .boot_device_fixup = uniphier_ld11_boot_device_fixup, + }, +#endif +}; +UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_boot_device_info, + uniphier_boot_device_info) + +static unsigned int __uniphier_boot_device_raw( + const struct uniphier_boot_device_info *info) +{ + u32 pinmon; + unsigned int boot_sel; + + if (boot_is_swapped()) + return BOOT_DEVICE_NOR; + + pinmon = readl(SG_PINMON0); + + if (info->boot_device_is_usb && info->boot_device_is_usb(pinmon)) + return BOOT_DEVICE_USB; + + boot_sel = pinmon >> info->boot_device_sel_shift; + + BUG_ON(!is_power_of_2(*info->boot_device_count)); + boot_sel &= *info->boot_device_count - 1; + + return info->boot_device_table[boot_sel].boot_device; +} + +unsigned int uniphier_boot_device_raw(void) +{ + const struct uniphier_boot_device_info *info; + + info = uniphier_get_boot_device_info(); + if (!info) { + pr_err("unsupported SoC\n"); + return BOOT_DEVICE_NONE; + } + + return __uniphier_boot_device_raw(info); +} + +u32 spl_boot_device(void) +{ + const struct uniphier_boot_device_info *info; + u32 raw_mode; + + info = uniphier_get_boot_device_info(); + if (!info) { + pr_err("unsupported SoC\n"); + return BOOT_DEVICE_NONE; + } + + raw_mode = __uniphier_boot_device_raw(info); + + return info->boot_device_fixup ? + info->boot_device_fixup(raw_mode) : raw_mode; +} + +#ifndef CONFIG_SPL_BUILD + +static int do_pinmon(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + const struct uniphier_boot_device_info *info; + u32 pinmon; + unsigned int boot_device_count, boot_sel; + int i; + + info = uniphier_get_boot_device_info(); + if (!info) { + pr_err("unsupported SoC\n"); + return CMD_RET_FAILURE; + } + + printf("Boot Swap: %s\n\n", boot_is_swapped() ? "ON" : "OFF"); + + pinmon = readl(SG_PINMON0); + + if (info->boot_device_is_usb) + printf("USB Boot: %s\n\n", + info->boot_device_is_usb(pinmon) ? "ON" : "OFF"); + + boot_device_count = *info->boot_device_count; + + boot_sel = pinmon >> info->boot_device_sel_shift; + boot_sel &= boot_device_count - 1; + + printf("Boot Mode Sel:\n"); + for (i = 0; i < boot_device_count; i++) + printf(" %c %02x %s\n", i == boot_sel ? '*' : ' ', i, + info->boot_device_table[i].desc); + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + pinmon, 1, 1, do_pinmon, + "pin monitor", + "" +); + +#endif /* !CONFIG_SPL_BUILD */ |