summaryrefslogtreecommitdiff
path: root/arch/arm/mach-uniphier/boot-device/boot-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-uniphier/boot-device/boot-device.c')
-rw-r--r--arch/arm/mach-uniphier/boot-device/boot-device.c206
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 */