aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/arch/arm/mach-meson
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/arch/arm/mach-meson')
-rw-r--r--roms/u-boot/arch/arm/mach-meson/Kconfig91
-rw-r--r--roms/u-boot/arch/arm/mach-meson/Makefile8
-rw-r--r--roms/u-boot/arch/arm/mach-meson/board-axg.c215
-rw-r--r--roms/u-boot/arch/arm/mach-meson/board-common.c189
-rw-r--r--roms/u-boot/arch/arm/mach-meson/board-g12a.c219
-rw-r--r--roms/u-boot/arch/arm/mach-meson/board-gx.c241
-rw-r--r--roms/u-boot/arch/arm/mach-meson/board-info.c202
-rw-r--r--roms/u-boot/arch/arm/mach-meson/sm.c220
8 files changed, 1385 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/mach-meson/Kconfig b/roms/u-boot/arch/arm/mach-meson/Kconfig
new file mode 100644
index 000000000..6cba2c40d
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-meson/Kconfig
@@ -0,0 +1,91 @@
+if ARCH_MESON
+
+config MESON64_COMMON
+ bool
+ select ARM64
+ select CLK
+ select DM
+ select DM_SERIAL
+ select SYSCON
+ select REGMAP
+ select PWRSEQ
+ select MMC_PWRSEQ
+ select BOARD_LATE_INIT
+ imply CMD_DM
+
+config MESON_GX
+ bool
+ select MESON64_COMMON
+
+choice
+ prompt "Platform select"
+ default MESON_GXBB
+
+config MESON_GXBB
+ bool "GXBB"
+ select MESON_GX
+ help
+ Select this if your SoC is an S905
+
+config MESON_GXL
+ bool "GXL"
+ select MESON_GX
+ help
+ Select this if your SoC is an S905X/D or S805X
+
+config MESON_GXM
+ bool "GXM"
+ select MESON_GX
+ help
+ Select this if your SoC is an S912
+
+config MESON_AXG
+ bool "AXG"
+ select MESON64_COMMON
+ help
+ Select this if your SoC is an A113X/D
+
+config MESON_G12A
+ bool "G12A"
+ select MESON64_COMMON
+ help
+ Select this if your SoC is an S905X/D2
+
+endchoice
+
+config SYS_SOC
+ default "meson"
+
+config SYS_MALLOC_F_LEN
+ default 0x1000
+
+config SYS_VENDOR
+ string "Vendor name"
+ default "amlogic"
+ help
+ This option contains information about board name.
+ Based on this option board/<CONFIG_SYS_VENDOR>/<CONFIG_SYS_BOARD> will
+ be used.
+
+config SYS_BOARD
+ string "Board name"
+ default "p200" if MESON_GXBB
+ default "p212" if MESON_GXL
+ default "q200" if MESON_GXM
+ default "s400" if MESON_AXG
+ default "u200" if MESON_G12A
+ default ""
+ help
+ This option contains information about board name.
+ Based on this option board/<CONFIG_SYS_VENDOR>/<CONFIG_SYS_BOARD> will
+ be used.
+
+config SYS_CONFIG_NAME
+ string "Board configuration name"
+ default "meson64"
+ help
+ This option contains information about board configuration name.
+ Based on this option include/configs/<CONFIG_SYS_CONFIG_NAME>.h header
+ will be used for board configuration.
+
+endif
diff --git a/roms/u-boot/arch/arm/mach-meson/Makefile b/roms/u-boot/arch/arm/mach-meson/Makefile
new file mode 100644
index 000000000..a9e4046f8
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-meson/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2016 Beniamino Galvani <b.galvani@gmail.com>
+
+obj-y += board-common.o sm.o board-info.o
+obj-$(CONFIG_MESON_GX) += board-gx.o
+obj-$(CONFIG_MESON_AXG) += board-axg.o
+obj-$(CONFIG_MESON_G12A) += board-g12a.o
diff --git a/roms/u-boot/arch/arm/mach-meson/board-axg.c b/roms/u-boot/arch/arm/mach-meson/board-axg.c
new file mode 100644
index 000000000..71ac65c63
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-meson/board-axg.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
+ * (C) Copyright 2018 Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <net.h>
+#include <asm/arch/boot.h>
+#include <asm/arch/eth.h>
+#include <asm/arch/axg.h>
+#include <asm/arch/mem.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/armv8/mmu.h>
+#include <linux/sizes.h>
+#include <usb.h>
+#include <linux/usb/otg.h>
+#include <asm/arch/usb-gx.h>
+#include <usb/dwc2_udc.h>
+#include <clk.h>
+#include <phy.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int meson_get_boot_device(void)
+{
+ return readl(AXG_AO_SEC_GP_CFG0) & AXG_AO_BOOT_DEVICE;
+}
+
+/* Configure the reserved memory zones exported by the secure registers
+ * into EFI and DTB reserved memory entries.
+ */
+void meson_init_reserved_memory(void *fdt)
+{
+ u64 bl31_size, bl31_start;
+ u64 bl32_size, bl32_start;
+ u32 reg;
+
+ /*
+ * Get ARM Trusted Firmware reserved memory zones in :
+ * - AO_SEC_GP_CFG3: bl32 & bl31 size in KiB, can be 0
+ * - AO_SEC_GP_CFG5: bl31 physical start address, can be NULL
+ * - AO_SEC_GP_CFG4: bl32 physical start address, can be NULL
+ */
+ reg = readl(AXG_AO_SEC_GP_CFG3);
+
+ bl31_size = ((reg & AXG_AO_BL31_RSVMEM_SIZE_MASK)
+ >> AXG_AO_BL31_RSVMEM_SIZE_SHIFT) * SZ_1K;
+ bl32_size = (reg & AXG_AO_BL32_RSVMEM_SIZE_MASK) * SZ_1K;
+
+ bl31_start = readl(AXG_AO_SEC_GP_CFG5);
+ bl32_start = readl(AXG_AO_SEC_GP_CFG4);
+
+ /* Add BL31 reserved zone */
+ if (bl31_start && bl31_size)
+ meson_board_add_reserved_memory(fdt, bl31_start, bl31_size);
+
+ /* Add BL32 reserved zone */
+ if (bl32_start && bl32_size)
+ meson_board_add_reserved_memory(fdt, bl32_start, bl32_size);
+}
+
+phys_size_t get_effective_memsize(void)
+{
+ /* Size is reported in MiB, convert it in bytes */
+ return ((readl(AXG_AO_SEC_GP_CFG0) & AXG_AO_MEM_SIZE_MASK)
+ >> AXG_AO_MEM_SIZE_SHIFT) * SZ_1M;
+}
+
+static struct mm_region axg_mem_map[] = {
+ {
+ .virt = 0x0UL,
+ .phys = 0x0UL,
+ .size = 0x80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ .virt = 0xf0000000UL,
+ .phys = 0xf0000000UL,
+ .size = 0x10000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+
+struct mm_region *mem_map = axg_mem_map;
+
+#if CONFIG_IS_ENABLED(USB_DWC3_MESON_GXL) && \
+ CONFIG_IS_ENABLED(USB_GADGET_DWC2_OTG)
+static struct dwc2_plat_otg_data meson_gx_dwc2_data;
+
+int board_usb_init(int index, enum usb_init_type init)
+{
+ struct fdtdec_phandle_args args;
+ const void *blob = gd->fdt_blob;
+ int node, dwc2_node;
+ struct udevice *dev, *clk_dev;
+ struct clk clk;
+ int ret;
+
+ /* find the usb glue node */
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "amlogic,meson-gxl-usb-ctrl");
+ if (node < 0) {
+ debug("Not found usb-control node\n");
+ return -ENODEV;
+ }
+
+ if (!fdtdec_get_is_enabled(blob, node)) {
+ debug("usb is disabled in the device tree\n");
+ return -ENODEV;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev);
+ if (ret) {
+ debug("Not found usb-control device\n");
+ return ret;
+ }
+
+ /* find the dwc2 node */
+ dwc2_node = fdt_node_offset_by_compatible(blob, node,
+ "amlogic,meson-g12a-usb");
+ if (dwc2_node < 0) {
+ debug("Not found dwc2 node\n");
+ return -ENODEV;
+ }
+
+ if (!fdtdec_get_is_enabled(blob, dwc2_node)) {
+ debug("dwc2 is disabled in the device tree\n");
+ return -ENODEV;
+ }
+
+ meson_gx_dwc2_data.regs_otg = fdtdec_get_addr(blob, dwc2_node, "reg");
+ if (meson_gx_dwc2_data.regs_otg == FDT_ADDR_T_NONE) {
+ debug("usbotg: can't get base address\n");
+ return -ENODATA;
+ }
+
+ /* Enable clock */
+ ret = fdtdec_parse_phandle_with_args(blob, dwc2_node, "clocks",
+ "#clock-cells", 0, 0, &args);
+ if (ret) {
+ debug("usbotg has no clocks defined in the device tree\n");
+ return ret;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &clk_dev);
+ if (ret)
+ return ret;
+
+ if (args.args_count != 1) {
+ debug("Can't find clock ID in the device tree\n");
+ return -ENODATA;
+ }
+
+ clk.dev = clk_dev;
+ clk.id = args.args[0];
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ debug("Failed to enable usbotg clock\n");
+ return ret;
+ }
+
+ meson_gx_dwc2_data.rx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
+ "g-rx-fifo-size", 0);
+ meson_gx_dwc2_data.np_tx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
+ "g-np-tx-fifo-size", 0);
+ meson_gx_dwc2_data.tx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
+ "g-tx-fifo-size", 0);
+
+ /* Switch to peripheral mode */
+ ret = dwc3_meson_gxl_force_mode(dev, USB_DR_MODE_PERIPHERAL);
+ if (ret)
+ return ret;
+
+ return dwc2_udc_probe(&meson_gx_dwc2_data);
+}
+
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+ const void *blob = gd->fdt_blob;
+ struct udevice *dev;
+ int node;
+ int ret;
+
+ /* find the usb glue node */
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "amlogic,meson-gxl-usb-ctrl");
+ if (node < 0) {
+ debug("Not found usb-control node\n");
+ return -ENODEV;
+ }
+
+ if (!fdtdec_get_is_enabled(blob, node))
+ return -ENODEV;
+
+ ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev);
+ if (ret)
+ return ret;
+
+ /* Switch to OTG mode */
+ ret = dwc3_meson_gxl_force_mode(dev, USB_DR_MODE_HOST);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/arch/arm/mach-meson/board-common.c b/roms/u-boot/arch/arm/mach-meson/board-common.c
new file mode 100644
index 000000000..1690b6b1e
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-meson/board-common.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <fastboot.h>
+#include <init.h>
+#include <net.h>
+#include <asm/arch/boot.h>
+#include <env.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/ptrace.h>
+#include <linux/libfdt.h>
+#include <linux/err.h>
+#include <asm/arch/mem.h>
+#include <asm/arch/sm.h>
+#include <asm/armv8/mmu.h>
+#include <asm/unaligned.h>
+#include <efi_loader.h>
+#include <u-boot/crc.h>
+
+#if CONFIG_IS_ENABLED(FASTBOOT)
+#include <asm/psci.h>
+#include <fastboot.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+__weak int board_init(void)
+{
+ return 0;
+}
+
+int dram_init(void)
+{
+ const fdt64_t *val;
+ int offset;
+ int len;
+
+ offset = fdt_path_offset(gd->fdt_blob, "/memory");
+ if (offset < 0)
+ return -EINVAL;
+
+ val = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
+ if (len < sizeof(*val) * 2)
+ return -EINVAL;
+
+ /* Use unaligned access since cache is still disabled */
+ gd->ram_size = get_unaligned_be64(&val[1]);
+
+ return 0;
+}
+
+__weak int meson_ft_board_setup(void *blob, struct bd_info *bd)
+{
+ return 0;
+}
+
+int ft_board_setup(void *blob, struct bd_info *bd)
+{
+ meson_init_reserved_memory(blob);
+
+ return meson_ft_board_setup(blob, bd);
+}
+
+void meson_board_add_reserved_memory(void *fdt, u64 start, u64 size)
+{
+ int ret;
+
+ ret = fdt_add_mem_rsv(fdt, start, size);
+ if (ret)
+ printf("Could not reserve zone @ 0x%llx\n", start);
+
+ if (IS_ENABLED(CONFIG_EFI_LOADER))
+ efi_add_memory_map(start, size, EFI_RESERVED_MEMORY_TYPE);
+}
+
+int meson_generate_serial_ethaddr(void)
+{
+ u8 mac_addr[ARP_HLEN];
+ char serial[SM_SERIAL_SIZE];
+ u32 sid;
+ u16 sid16;
+
+ if (!meson_sm_get_serial(serial, SM_SERIAL_SIZE)) {
+ sid = crc32(0, (unsigned char *)serial, SM_SERIAL_SIZE);
+ sid16 = crc16_ccitt(0, (unsigned char *)serial, SM_SERIAL_SIZE);
+
+ /* Ensure the NIC specific bytes of the mac are not all 0 */
+ if ((sid & 0xffffff) == 0)
+ sid |= 0x800000;
+
+ /* Non OUI / registered MAC address */
+ mac_addr[0] = ((sid16 >> 8) & 0xfc) | 0x02;
+ mac_addr[1] = (sid16 >> 0) & 0xff;
+ mac_addr[2] = (sid >> 24) & 0xff;
+ mac_addr[3] = (sid >> 16) & 0xff;
+ mac_addr[4] = (sid >> 8) & 0xff;
+ mac_addr[5] = (sid >> 0) & 0xff;
+
+ eth_env_set_enetaddr("ethaddr", mac_addr);
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
+static void meson_set_boot_source(void)
+{
+ const char *source;
+
+ switch (meson_get_boot_device()) {
+ case BOOT_DEVICE_EMMC:
+ source = "emmc";
+ break;
+
+ case BOOT_DEVICE_NAND:
+ source = "nand";
+ break;
+
+ case BOOT_DEVICE_SPI:
+ source = "spi";
+ break;
+
+ case BOOT_DEVICE_SD:
+ source = "sd";
+ break;
+
+ case BOOT_DEVICE_USB:
+ source = "usb";
+ break;
+
+ default:
+ source = "unknown";
+ }
+
+ env_set("boot_source", source);
+}
+
+__weak int meson_board_late_init(void)
+{
+ return 0;
+}
+
+int board_late_init(void)
+{
+ meson_set_boot_source();
+
+ return meson_board_late_init();
+}
+
+#if CONFIG_IS_ENABLED(FASTBOOT)
+static unsigned int reboot_reason = REBOOT_REASON_NORMAL;
+
+int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
+{
+ if (reason != FASTBOOT_REBOOT_REASON_BOOTLOADER)
+ return -ENOTSUPP;
+
+ reboot_reason = REBOOT_REASON_BOOTLOADER;
+
+ printf("Using reboot reason: 0x%x\n", reboot_reason);
+
+ return 0;
+}
+
+void reset_cpu(void)
+{
+ struct pt_regs regs;
+
+ regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET;
+ regs.regs[1] = reboot_reason;
+
+ printf("Rebooting with reason: 0x%lx\n", regs.regs[1]);
+
+ smc_call(&regs);
+
+ while (1)
+ ;
+}
+#else
+void reset_cpu(void)
+{
+ psci_system_reset();
+}
+#endif
diff --git a/roms/u-boot/arch/arm/mach-meson/board-g12a.c b/roms/u-boot/arch/arm/mach-meson/board-g12a.c
new file mode 100644
index 000000000..2e59eee8f
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-meson/board-g12a.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
+ * (C) Copyright 2018 Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <log.h>
+#include <net.h>
+#include <asm/arch/boot.h>
+#include <asm/arch/eth.h>
+#include <asm/arch/g12a.h>
+#include <asm/arch/mem.h>
+#include <asm/arch/meson-vpu.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/armv8/mmu.h>
+#include <linux/sizes.h>
+#include <usb.h>
+#include <linux/usb/otg.h>
+#include <asm/arch/usb.h>
+#include <usb/dwc2_udc.h>
+#include <phy.h>
+#include <clk.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int meson_get_boot_device(void)
+{
+ return readl(G12A_AO_SEC_GP_CFG0) & G12A_AO_BOOT_DEVICE;
+}
+
+/* Configure the reserved memory zones exported by the secure registers
+ * into EFI and DTB reserved memory entries.
+ */
+void meson_init_reserved_memory(void *fdt)
+{
+ u64 bl31_size, bl31_start;
+ u64 bl32_size, bl32_start;
+ u32 reg;
+
+ /*
+ * Get ARM Trusted Firmware reserved memory zones in :
+ * - AO_SEC_GP_CFG3: bl32 & bl31 size in KiB, can be 0
+ * - AO_SEC_GP_CFG5: bl31 physical start address, can be NULL
+ * - AO_SEC_GP_CFG4: bl32 physical start address, can be NULL
+ */
+ reg = readl(G12A_AO_SEC_GP_CFG3);
+
+ bl31_size = ((reg & G12A_AO_BL31_RSVMEM_SIZE_MASK)
+ >> G12A_AO_BL31_RSVMEM_SIZE_SHIFT) * SZ_1K;
+ bl32_size = (reg & G12A_AO_BL32_RSVMEM_SIZE_MASK) * SZ_1K;
+
+ bl31_start = readl(G12A_AO_SEC_GP_CFG5);
+ bl32_start = readl(G12A_AO_SEC_GP_CFG4);
+
+ /* Add BL31 reserved zone */
+ if (bl31_start && bl31_size)
+ meson_board_add_reserved_memory(fdt, bl31_start, bl31_size);
+
+ /* Add BL32 reserved zone */
+ if (bl32_start && bl32_size)
+ meson_board_add_reserved_memory(fdt, bl32_start, bl32_size);
+
+#if defined(CONFIG_VIDEO_MESON)
+ meson_vpu_rsv_fb(fdt);
+#endif
+}
+
+phys_size_t get_effective_memsize(void)
+{
+ /* Size is reported in MiB, convert it in bytes */
+ return min(((readl(G12A_AO_SEC_GP_CFG0) & G12A_AO_MEM_SIZE_MASK)
+ >> G12A_AO_MEM_SIZE_SHIFT) * SZ_1M, 0xf5000000);
+}
+
+static struct mm_region g12a_mem_map[] = {
+ {
+ .virt = 0x0UL,
+ .phys = 0x0UL,
+ .size = 0xf5000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ .virt = 0xf5000000UL,
+ .phys = 0xf5000000UL,
+ .size = 0x0b000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+
+struct mm_region *mem_map = g12a_mem_map;
+
+#if CONFIG_IS_ENABLED(USB_DWC3_MESON_G12A) && \
+ CONFIG_IS_ENABLED(USB_GADGET_DWC2_OTG)
+static struct dwc2_plat_otg_data meson_g12a_dwc2_data;
+
+int board_usb_init(int index, enum usb_init_type init)
+{
+ struct fdtdec_phandle_args args;
+ const void *blob = gd->fdt_blob;
+ int node, dwc2_node;
+ struct udevice *dev, *clk_dev;
+ struct clk clk;
+ int ret;
+
+ /* find the usb glue node */
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "amlogic,meson-g12a-usb-ctrl");
+ if (node < 0) {
+ debug("Not found usb-control node\n");
+ return -ENODEV;
+ }
+
+ if (!fdtdec_get_is_enabled(blob, node)) {
+ debug("usb is disabled in the device tree\n");
+ return -ENODEV;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev);
+ if (ret) {
+ debug("Not found usb-control device\n");
+ return ret;
+ }
+
+ /* find the dwc2 node */
+ dwc2_node = fdt_node_offset_by_compatible(blob, node,
+ "amlogic,meson-g12a-usb");
+ if (dwc2_node < 0) {
+ debug("Not found dwc2 node\n");
+ return -ENODEV;
+ }
+
+ if (!fdtdec_get_is_enabled(blob, dwc2_node)) {
+ debug("dwc2 is disabled in the device tree\n");
+ return -ENODEV;
+ }
+
+ meson_g12a_dwc2_data.regs_otg = fdtdec_get_addr(blob, dwc2_node, "reg");
+ if (meson_g12a_dwc2_data.regs_otg == FDT_ADDR_T_NONE) {
+ debug("usbotg: can't get base address\n");
+ return -ENODATA;
+ }
+
+ /* Enable clock */
+ ret = fdtdec_parse_phandle_with_args(blob, dwc2_node, "clocks",
+ "#clock-cells", 0, 0, &args);
+ if (ret) {
+ debug("usbotg has no clocks defined in the device tree\n");
+ return ret;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &clk_dev);
+ if (ret)
+ return ret;
+
+ if (args.args_count != 1) {
+ debug("Can't find clock ID in the device tree\n");
+ return -ENODATA;
+ }
+
+ clk.dev = clk_dev;
+ clk.id = args.args[0];
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ debug("Failed to enable usbotg clock\n");
+ return ret;
+ }
+
+ meson_g12a_dwc2_data.rx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
+ "g-rx-fifo-size", 0);
+ meson_g12a_dwc2_data.np_tx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
+ "g-np-tx-fifo-size", 0);
+ meson_g12a_dwc2_data.tx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
+ "g-tx-fifo-size", 0);
+
+ /* Switch to peripheral mode */
+ ret = dwc3_meson_g12a_force_mode(dev, USB_DR_MODE_PERIPHERAL);
+ if (ret)
+ return ret;
+
+ return dwc2_udc_probe(&meson_g12a_dwc2_data);
+}
+
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+ const void *blob = gd->fdt_blob;
+ struct udevice *dev;
+ int node;
+ int ret;
+
+ /* find the usb glue node */
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "amlogic,meson-g12a-usb-ctrl");
+ if (node < 0)
+ return -ENODEV;
+
+ if (!fdtdec_get_is_enabled(blob, node))
+ return -ENODEV;
+
+ ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev);
+ if (ret)
+ return ret;
+
+ /* Switch to OTG mode */
+ ret = dwc3_meson_g12a_force_mode(dev, USB_DR_MODE_HOST);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/arch/arm/mach-meson/board-gx.c b/roms/u-boot/arch/arm/mach-meson/board-gx.c
new file mode 100644
index 000000000..01fafd81c
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-meson/board-gx.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
+ * (C) Copyright 2018 Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <net.h>
+#include <asm/arch/boot.h>
+#include <asm/arch/eth.h>
+#include <asm/arch/gx.h>
+#include <asm/arch/mem.h>
+#include <asm/arch/meson-vpu.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/armv8/mmu.h>
+#include <linux/sizes.h>
+#include <usb.h>
+#include <linux/usb/otg.h>
+#include <asm/arch/usb-gx.h>
+#include <usb/dwc2_udc.h>
+#include <clk.h>
+#include <phy.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int meson_get_boot_device(void)
+{
+ return readl(GX_AO_SEC_GP_CFG0) & GX_AO_BOOT_DEVICE;
+}
+
+/* Configure the reserved memory zones exported by the secure registers
+ * into EFI and DTB reserved memory entries.
+ */
+void meson_init_reserved_memory(void *fdt)
+{
+ u64 bl31_size, bl31_start;
+ u64 bl32_size, bl32_start;
+ u32 reg;
+
+ /*
+ * Get ARM Trusted Firmware reserved memory zones in :
+ * - AO_SEC_GP_CFG3: bl32 & bl31 size in KiB, can be 0
+ * - AO_SEC_GP_CFG5: bl31 physical start address, can be NULL
+ * - AO_SEC_GP_CFG4: bl32 physical start address, can be NULL
+ */
+ reg = readl(GX_AO_SEC_GP_CFG3);
+
+ bl31_size = ((reg & GX_AO_BL31_RSVMEM_SIZE_MASK)
+ >> GX_AO_BL31_RSVMEM_SIZE_SHIFT) * SZ_1K;
+ bl32_size = (reg & GX_AO_BL32_RSVMEM_SIZE_MASK) * SZ_1K;
+
+ bl31_start = readl(GX_AO_SEC_GP_CFG5);
+ bl32_start = readl(GX_AO_SEC_GP_CFG4);
+
+ /*
+ * Early Meson GX Firmware revisions did not provide the reserved
+ * memory zones in the registers, keep fixed memory zone handling.
+ */
+ if (IS_ENABLED(CONFIG_MESON_GX) &&
+ !reg && !bl31_start && !bl32_start) {
+ bl31_start = 0x10000000;
+ bl31_size = 0x200000;
+ }
+
+ /* Add first 16MiB reserved zone */
+ meson_board_add_reserved_memory(fdt, 0, GX_FIRMWARE_MEM_SIZE);
+
+ /* Add BL31 reserved zone */
+ if (bl31_start && bl31_size)
+ meson_board_add_reserved_memory(fdt, bl31_start, bl31_size);
+
+ /* Add BL32 reserved zone */
+ if (bl32_start && bl32_size)
+ meson_board_add_reserved_memory(fdt, bl32_start, bl32_size);
+
+#if defined(CONFIG_VIDEO_MESON)
+ meson_vpu_rsv_fb(fdt);
+#endif
+}
+
+phys_size_t get_effective_memsize(void)
+{
+ /* Size is reported in MiB, convert it in bytes */
+ return ((readl(GX_AO_SEC_GP_CFG0) & GX_AO_MEM_SIZE_MASK)
+ >> GX_AO_MEM_SIZE_SHIFT) * SZ_1M;
+}
+
+static struct mm_region gx_mem_map[] = {
+ {
+ .virt = 0x0UL,
+ .phys = 0x0UL,
+ .size = 0xc0000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ .virt = 0xc0000000UL,
+ .phys = 0xc0000000UL,
+ .size = 0x30000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+
+struct mm_region *mem_map = gx_mem_map;
+
+#if CONFIG_IS_ENABLED(USB_DWC3_MESON_GXL) && \
+ CONFIG_IS_ENABLED(USB_GADGET_DWC2_OTG)
+static struct dwc2_plat_otg_data meson_gx_dwc2_data;
+
+int board_usb_init(int index, enum usb_init_type init)
+{
+ struct fdtdec_phandle_args args;
+ const void *blob = gd->fdt_blob;
+ int node, dwc2_node;
+ struct udevice *dev, *clk_dev;
+ struct clk clk;
+ int ret;
+
+ /* find the usb glue node */
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "amlogic,meson-gxl-usb-ctrl");
+ if (node < 0) {
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "amlogic,meson-gxm-usb-ctrl");
+ if (node < 0) {
+ debug("Not found usb-control node\n");
+ return -ENODEV;
+ }
+ }
+
+ if (!fdtdec_get_is_enabled(blob, node)) {
+ debug("usb is disabled in the device tree\n");
+ return -ENODEV;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev);
+ if (ret) {
+ debug("Not found usb-control device\n");
+ return ret;
+ }
+
+ /* find the dwc2 node */
+ dwc2_node = fdt_node_offset_by_compatible(blob, node,
+ "amlogic,meson-g12a-usb");
+ if (dwc2_node < 0) {
+ debug("Not found dwc2 node\n");
+ return -ENODEV;
+ }
+
+ if (!fdtdec_get_is_enabled(blob, dwc2_node)) {
+ debug("dwc2 is disabled in the device tree\n");
+ return -ENODEV;
+ }
+
+ meson_gx_dwc2_data.regs_otg = fdtdec_get_addr(blob, dwc2_node, "reg");
+ if (meson_gx_dwc2_data.regs_otg == FDT_ADDR_T_NONE) {
+ debug("usbotg: can't get base address\n");
+ return -ENODATA;
+ }
+
+ /* Enable clock */
+ ret = fdtdec_parse_phandle_with_args(blob, dwc2_node, "clocks",
+ "#clock-cells", 0, 0, &args);
+ if (ret) {
+ debug("usbotg has no clocks defined in the device tree\n");
+ return ret;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &clk_dev);
+ if (ret)
+ return ret;
+
+ if (args.args_count != 1) {
+ debug("Can't find clock ID in the device tree\n");
+ return -ENODATA;
+ }
+
+ clk.dev = clk_dev;
+ clk.id = args.args[0];
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ debug("Failed to enable usbotg clock\n");
+ return ret;
+ }
+
+ meson_gx_dwc2_data.rx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
+ "g-rx-fifo-size", 0);
+ meson_gx_dwc2_data.np_tx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
+ "g-np-tx-fifo-size", 0);
+ meson_gx_dwc2_data.tx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
+ "g-tx-fifo-size", 0);
+
+ /* Switch to peripheral mode */
+ ret = dwc3_meson_gxl_force_mode(dev, USB_DR_MODE_PERIPHERAL);
+ if (ret)
+ return ret;
+
+ return dwc2_udc_probe(&meson_gx_dwc2_data);
+}
+
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+ const void *blob = gd->fdt_blob;
+ struct udevice *dev;
+ int node;
+ int ret;
+
+ /* find the usb glue node */
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "amlogic,meson-gxl-usb-ctrl");
+ if (node < 0) {
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "amlogic,meson-gxm-usb-ctrl");
+ if (node < 0) {
+ debug("Not found usb-control node\n");
+ return -ENODEV;
+ }
+ }
+
+ if (!fdtdec_get_is_enabled(blob, node))
+ return -ENODEV;
+
+ ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev);
+ if (ret)
+ return ret;
+
+ /* Switch to OTG mode */
+ ret = dwc3_meson_gxl_force_mode(dev, USB_DR_MODE_HOST);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/arch/arm/mach-meson/board-info.c b/roms/u-boot/arch/arm/mach-meson/board-info.c
new file mode 100644
index 000000000..d16d3f194
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-meson/board-info.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Julien Masson <jmasson@baylibre.com>
+ * (C) Copyright 2019 Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <linux/bitfield.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+#define AO_SEC_SD_CFG8 0xe0
+#define AO_SEC_SOCINFO_OFFSET AO_SEC_SD_CFG8
+
+#define SOCINFO_MAJOR GENMASK(31, 24)
+#define SOCINFO_PACK GENMASK(23, 16)
+#define SOCINFO_MINOR GENMASK(15, 8)
+#define SOCINFO_MISC GENMASK(7, 0)
+
+static const struct meson_gx_soc_id {
+ const char *name;
+ unsigned int id;
+} soc_ids[] = {
+ { "GXBB", 0x1f },
+ { "GXTVBB", 0x20 },
+ { "GXL", 0x21 },
+ { "GXM", 0x22 },
+ { "TXL", 0x23 },
+ { "TXLX", 0x24 },
+ { "AXG", 0x25 },
+ { "GXLX", 0x26 },
+ { "TXHD", 0x27 },
+ { "G12A", 0x28 },
+ { "G12B", 0x29 },
+ { "SM1", 0x2b },
+ { "A1", 0x2c },
+};
+
+static const struct meson_gx_package_id {
+ const char *name;
+ unsigned int major_id;
+ unsigned int pack_id;
+ unsigned int pack_mask;
+} soc_packages[] = {
+ { "S905", 0x1f, 0, 0x20 }, /* pack_id != 0x20 */
+ { "S905H", 0x1f, 0x3, 0xf }, /* pack_id & 0xf == 0x3 */
+ { "S905M", 0x1f, 0x20, 0xf0 }, /* pack_id == 0x20 */
+ { "S905D", 0x21, 0, 0xf0 },
+ { "S905X", 0x21, 0x80, 0xf0 },
+ { "S905W", 0x21, 0xa0, 0xf0 },
+ { "S905L", 0x21, 0xc0, 0xf0 },
+ { "S905M2", 0x21, 0xe0, 0xf0 },
+ { "S805X", 0x21, 0x30, 0xf0 },
+ { "S805Y", 0x21, 0xb0, 0xf0 },
+ { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */
+ { "962X", 0x24, 0x10, 0xf0 },
+ { "962E", 0x24, 0x20, 0xf0 },
+ { "A113X", 0x25, 0x37, 0xff },
+ { "A113D", 0x25, 0x22, 0xff },
+ { "S905D2", 0x28, 0x10, 0xf0 },
+ { "S905X2", 0x28, 0x40, 0xf0 },
+ { "A311D", 0x29, 0x10, 0xf0 },
+ { "S922X", 0x29, 0x40, 0xf0 },
+ { "S905D3", 0x2b, 0x4, 0xf5 },
+ { "S905X3", 0x2b, 0x5, 0xf5 },
+ { "S905X3", 0x2b, 0x10, 0x3f },
+ { "S905D3", 0x2b, 0x30, 0x3f },
+ { "A113L", 0x2c, 0x0, 0xf8 },
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline unsigned int socinfo_to_major(u32 socinfo)
+{
+ return FIELD_GET(SOCINFO_MAJOR, socinfo);
+}
+
+static inline unsigned int socinfo_to_minor(u32 socinfo)
+{
+ return FIELD_GET(SOCINFO_MINOR, socinfo);
+}
+
+static inline unsigned int socinfo_to_pack(u32 socinfo)
+{
+ return FIELD_GET(SOCINFO_PACK, socinfo);
+}
+
+static inline unsigned int socinfo_to_misc(u32 socinfo)
+{
+ return FIELD_GET(SOCINFO_MISC, socinfo);
+}
+
+static const char *socinfo_to_package_id(u32 socinfo)
+{
+ unsigned int pack = socinfo_to_pack(socinfo);
+ unsigned int major = socinfo_to_major(socinfo);
+ int i;
+
+ for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) {
+ if (soc_packages[i].major_id == major &&
+ soc_packages[i].pack_id ==
+ (pack & soc_packages[i].pack_mask))
+ return soc_packages[i].name;
+ }
+
+ return "Unknown";
+}
+
+static const char *socinfo_to_soc_id(u32 socinfo)
+{
+ unsigned int id = socinfo_to_major(socinfo);
+ int i;
+
+ for (i = 0 ; i < ARRAY_SIZE(soc_ids) ; ++i) {
+ if (soc_ids[i].id == id)
+ return soc_ids[i].name;
+ }
+
+ return "Unknown";
+}
+
+static void print_board_model(void)
+{
+ const char *model;
+ model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
+ printf("Model: %s\n", model ? model : "Unknown");
+}
+
+static unsigned int get_socinfo(void)
+{
+ struct regmap *regmap;
+ int nodeoffset, ret;
+ ofnode node;
+ unsigned int socinfo;
+
+ /* find the offset of compatible node */
+ nodeoffset = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
+ "amlogic,meson-gx-ao-secure");
+ if (nodeoffset < 0)
+ return 0;
+
+ /* check if chip-id is available */
+ if (!fdt_getprop(gd->fdt_blob, nodeoffset, "amlogic,has-chip-id", NULL))
+ return 0;
+
+ /* get regmap from the syscon node */
+ node = offset_to_ofnode(nodeoffset);
+ regmap = syscon_node_to_regmap(node);
+ if (IS_ERR(regmap)) {
+ printf("%s: failed to get regmap\n", __func__);
+ return 0;
+ }
+
+ /* read soc info */
+ ret = regmap_read(regmap, AO_SEC_SOCINFO_OFFSET, &socinfo);
+ if (ret && !socinfo) {
+ printf("%s: invalid chipid value\n", __func__);
+ return 0;
+ }
+
+ return socinfo;
+}
+
+int show_board_info(void)
+{
+ unsigned int socinfo;
+
+ /* print board information */
+ print_board_model();
+
+ socinfo = get_socinfo();
+ if (!socinfo)
+ return 0;
+
+ printf("SoC: Amlogic Meson %s (%s) Revision %x:%x (%x:%x)\n",
+ socinfo_to_soc_id(socinfo),
+ socinfo_to_package_id(socinfo),
+ socinfo_to_major(socinfo),
+ socinfo_to_minor(socinfo),
+ socinfo_to_pack(socinfo),
+ socinfo_to_misc(socinfo));
+
+ return 0;
+}
+
+int meson_get_soc_rev(char *buff, size_t buff_len)
+{
+ unsigned int socinfo;
+
+ socinfo = get_socinfo();
+ if (!socinfo)
+ return -1;
+
+ /* Write SoC info */
+ return snprintf(buff, buff_len, "%x", socinfo_to_minor(socinfo));
+}
diff --git a/roms/u-boot/arch/arm/mach-meson/sm.c b/roms/u-boot/arch/arm/mach-meson/sm.c
new file mode 100644
index 000000000..1a8f23cb1
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-meson/sm.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
+ *
+ * Secure monitor calls.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <env.h>
+#include <log.h>
+#include <asm/arch/sm.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/ptrace.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <dm.h>
+#include <linux/bitfield.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#define FN_GET_SHARE_MEM_INPUT_BASE 0x82000020
+#define FN_GET_SHARE_MEM_OUTPUT_BASE 0x82000021
+#define FN_EFUSE_READ 0x82000030
+#define FN_EFUSE_WRITE 0x82000031
+#define FN_CHIP_ID 0x82000044
+
+static void *shmem_input;
+static void *shmem_output;
+
+static void meson_init_shmem(void)
+{
+ struct pt_regs regs;
+
+ if (shmem_input && shmem_output)
+ return;
+
+ regs.regs[0] = FN_GET_SHARE_MEM_INPUT_BASE;
+ smc_call(&regs);
+ shmem_input = (void *)regs.regs[0];
+
+ regs.regs[0] = FN_GET_SHARE_MEM_OUTPUT_BASE;
+ smc_call(&regs);
+ shmem_output = (void *)regs.regs[0];
+
+ debug("Secure Monitor shmem: 0x%p 0x%p\n", shmem_input, shmem_output);
+}
+
+ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size)
+{
+ struct pt_regs regs;
+
+ meson_init_shmem();
+
+ regs.regs[0] = FN_EFUSE_READ;
+ regs.regs[1] = offset;
+ regs.regs[2] = size;
+
+ smc_call(&regs);
+
+ if (regs.regs[0] == 0)
+ return -1;
+
+ memcpy(buffer, shmem_output, min(size, regs.regs[0]));
+
+ return regs.regs[0];
+}
+
+#define SM_CHIP_ID_LENGTH 119
+#define SM_CHIP_ID_OFFSET 4
+#define SM_CHIP_ID_SIZE 12
+
+int meson_sm_get_serial(void *buffer, size_t size)
+{
+ struct pt_regs regs;
+
+ meson_init_shmem();
+
+ regs.regs[0] = FN_CHIP_ID;
+ regs.regs[1] = 0;
+ regs.regs[2] = 0;
+
+ smc_call(&regs);
+
+ memcpy(buffer, shmem_output + SM_CHIP_ID_OFFSET,
+ min_t(size_t, size, SM_CHIP_ID_SIZE));
+
+ return 0;
+}
+
+#define AO_SEC_SD_CFG15 0xfc
+#define REBOOT_REASON_MASK GENMASK(15, 12)
+
+int meson_sm_get_reboot_reason(void)
+{
+ struct regmap *regmap;
+ int nodeoffset;
+ ofnode node;
+ unsigned int reason;
+
+ /* find the offset of compatible node */
+ nodeoffset = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
+ "amlogic,meson-gx-ao-secure");
+ if (nodeoffset < 0) {
+ printf("%s: failed to get amlogic,meson-gx-ao-secure\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ /* get regmap from the syscon node */
+ node = offset_to_ofnode(nodeoffset);
+ regmap = syscon_node_to_regmap(node);
+ if (IS_ERR(regmap)) {
+ printf("%s: failed to get regmap\n", __func__);
+ return -EINVAL;
+ }
+
+ regmap_read(regmap, AO_SEC_SD_CFG15, &reason);
+
+ /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */
+ return FIELD_GET(REBOOT_REASON_MASK, reason);
+}
+
+static int do_sm_serial(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ ulong address;
+ int ret;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ address = simple_strtoul(argv[1], NULL, 0);
+
+ ret = meson_sm_get_serial((void *)address, SM_CHIP_ID_SIZE);
+ if (ret)
+ return CMD_RET_FAILURE;
+
+ return CMD_RET_SUCCESS;
+}
+
+#define MAX_REBOOT_REASONS 14
+
+static const char *reboot_reasons[MAX_REBOOT_REASONS] = {
+ [REBOOT_REASON_COLD] = "cold_boot",
+ [REBOOT_REASON_NORMAL] = "normal",
+ [REBOOT_REASON_RECOVERY] = "recovery",
+ [REBOOT_REASON_UPDATE] = "update",
+ [REBOOT_REASON_FASTBOOT] = "fastboot",
+ [REBOOT_REASON_SUSPEND_OFF] = "suspend_off",
+ [REBOOT_REASON_HIBERNATE] = "hibernate",
+ [REBOOT_REASON_BOOTLOADER] = "bootloader",
+ [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot",
+ [REBOOT_REASON_RPMBP] = "rpmbp",
+ [REBOOT_REASON_CRASH_DUMP] = "crash_dump",
+ [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic",
+ [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot",
+};
+
+static int do_sm_reboot_reason(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ const char *reason_str;
+ char *destarg = NULL;
+ int reason;
+
+ if (argc > 1)
+ destarg = argv[1];
+
+ reason = meson_sm_get_reboot_reason();
+ if (reason < 0)
+ return CMD_RET_FAILURE;
+
+ if (reason >= MAX_REBOOT_REASONS ||
+ !reboot_reasons[reason])
+ reason_str = "unknown";
+ else
+ reason_str = reboot_reasons[reason];
+
+ if (destarg)
+ env_set(destarg, reason_str);
+ else
+ printf("reboot reason: %s (%x)\n", reason_str, reason);
+
+ return CMD_RET_SUCCESS;
+}
+
+static struct cmd_tbl cmd_sm_sub[] = {
+ U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""),
+ U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""),
+};
+
+static int do_sm(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct cmd_tbl *c;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ /* Strip off leading 'sm' command argument */
+ argc--;
+ argv++;
+
+ c = find_cmd_tbl(argv[0], &cmd_sm_sub[0], ARRAY_SIZE(cmd_sm_sub));
+
+ if (c)
+ return c->cmd(cmdtp, flag, argc, argv);
+ else
+ return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(
+ sm, 5, 0, do_sm,
+ "Secure Monitor Control",
+ "serial <address> - read chip unique id to memory address\n"
+ "sm reboot_reason [name] - get reboot reason and store to to environment"
+);