diff options
Diffstat (limited to 'roms/u-boot/arch/arm/mach-meson')
-rw-r--r-- | roms/u-boot/arch/arm/mach-meson/Kconfig | 91 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-meson/Makefile | 8 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-meson/board-axg.c | 215 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-meson/board-common.c | 189 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-meson/board-g12a.c | 219 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-meson/board-gx.c | 241 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-meson/board-info.c | 202 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-meson/sm.c | 220 |
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(®s); + + 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(®s); + shmem_input = (void *)regs.regs[0]; + + regs.regs[0] = FN_GET_SHARE_MEM_OUTPUT_BASE; + smc_call(®s); + 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(®s); + + 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(®s); + + 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" +); |