arm64: versal2: Add support for AMD Versal Gen 2
Add support for AMD Versal Gen 2. SoC is based on Cortex-a78ae 4 cluster/2 cpu core each. A lot of IPs are shared with previous families. There are couple of new IP blocks where the most interesting from user point of view is UFS. Signed-off-by: Michal Simek <michal.simek@amd.com> Link: https://lore.kernel.org/r/bc2b70831ce1031bd0fac32357bff84936e1310f.1716994063.git.michal.simek@amd.com
This commit is contained in:
1
board/amd/common
Symbolic link
1
board/amd/common
Symbolic link
@@ -0,0 +1 @@
|
||||
../xilinx/common/
|
16
board/amd/versal2/Kconfig
Normal file
16
board/amd/versal2/Kconfig
Normal file
@@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (C) 2020 - 2022, Xilinx, Inc.
|
||||
# Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc.
|
||||
#
|
||||
if ARCH_VERSAL2
|
||||
|
||||
config CMD_VERSAL2
|
||||
bool "Enable Versal Gen 2 specific commands"
|
||||
default y
|
||||
depends on ZYNQMP_FIRMWARE
|
||||
help
|
||||
Select this to enable AMD Versal Gen 2 specific commands.
|
||||
Commands like versal2 loadpdi are enabled by this.
|
||||
|
||||
endif
|
7
board/amd/versal2/MAINTAINERS
Normal file
7
board/amd/versal2/MAINTAINERS
Normal file
@@ -0,0 +1,7 @@
|
||||
XILINX_VERSAL2 BOARDS
|
||||
M: Michal Simek <michal.simek@amd.com>
|
||||
S: Maintained
|
||||
T: git https://gitlab.denx.de/u-boot/custodians/u-boot-microblaze.git
|
||||
F: arch/arm/dts/versal2*
|
||||
F: board/amd/
|
||||
F: configs/amd*
|
11
board/amd/versal2/Makefile
Normal file
11
board/amd/versal2/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (C) 2021 - 2022, Xilinx, Inc.
|
||||
# Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc.
|
||||
#
|
||||
# Michal Simek <michal.simek@amd.com>
|
||||
#
|
||||
|
||||
obj-y := board.o
|
||||
|
||||
obj-$(CONFIG_CMD_VERSAL2) += cmds.o
|
343
board/amd/versal2/board.c
Normal file
343
board/amd/versal2/board.c
Normal file
@@ -0,0 +1,343 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021 - 2022, Xilinx, Inc.
|
||||
* Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Michal Simek <michal.simek@amd.com>
|
||||
*/
|
||||
|
||||
#include <cpu_func.h>
|
||||
#include <fdtdec.h>
|
||||
#include <init.h>
|
||||
#include <env_internal.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/uclass.h>
|
||||
#include "../../xilinx/common/board.h"
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <debug_uart.h>
|
||||
#include <generated/dt.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int board_init(void)
|
||||
{
|
||||
printf("EL Level:\tEL%d\n", current_el());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 platform_id, platform_version;
|
||||
|
||||
char *soc_name_decode(void)
|
||||
{
|
||||
char *name, *platform_name;
|
||||
|
||||
switch (platform_id) {
|
||||
case VERSAL2_SPP:
|
||||
platform_name = "spp";
|
||||
break;
|
||||
case VERSAL2_EMU:
|
||||
platform_name = "emu";
|
||||
break;
|
||||
case VERSAL2_SPP_MMD:
|
||||
platform_name = "spp-mmd";
|
||||
break;
|
||||
case VERSAL2_EMU_MMD:
|
||||
platform_name = "emu-mmd";
|
||||
break;
|
||||
case VERSAL2_QEMU:
|
||||
platform_name = "qemu";
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* --rev. are 6 chars
|
||||
* max platform name is qemu which is 4 chars
|
||||
* platform version number are 1+1
|
||||
* Plus 1 char for \n
|
||||
*/
|
||||
name = calloc(1, strlen(CONFIG_SYS_BOARD) + 13);
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
sprintf(name, "%s-%s-rev%d.%d-el%d", CONFIG_SYS_BOARD,
|
||||
platform_name, platform_version / 10,
|
||||
platform_version % 10, current_el());
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool soc_detection(void)
|
||||
{
|
||||
u32 version, ps_version;
|
||||
|
||||
version = readl(PMC_TAP_VERSION);
|
||||
platform_id = FIELD_GET(PLATFORM_MASK, version);
|
||||
ps_version = FIELD_GET(PS_VERSION_MASK, version);
|
||||
|
||||
debug("idcode %x, version %x, usercode %x\n",
|
||||
readl(PMC_TAP_IDCODE), version,
|
||||
readl(PMC_TAP_USERCODE));
|
||||
|
||||
debug("pmc_ver %lx, ps version %x, rtl version %lx\n",
|
||||
FIELD_GET(PMC_VERSION_MASK, version),
|
||||
ps_version,
|
||||
FIELD_GET(RTL_VERSION_MASK, version));
|
||||
|
||||
platform_version = FIELD_GET(PLATFORM_VERSION_MASK, version);
|
||||
|
||||
debug("Platform id: %d version: %d.%d\n", platform_id,
|
||||
platform_version / 10, platform_version % 10);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int board_early_init_r(void)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (current_el() != 3)
|
||||
return 0;
|
||||
|
||||
debug("iou_switch ctrl div0 %x\n",
|
||||
readl(&crlapb_base->iou_switch_ctrl));
|
||||
|
||||
writel(IOU_SWITCH_CTRL_CLKACT_BIT |
|
||||
(CONFIG_IOU_SWITCH_DIVISOR0 << IOU_SWITCH_CTRL_DIVISOR0_SHIFT),
|
||||
&crlapb_base->iou_switch_ctrl);
|
||||
|
||||
/* Global timer init - Program time stamp reference clk */
|
||||
val = readl(&crlapb_base->timestamp_ref_ctrl);
|
||||
val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT;
|
||||
writel(val, &crlapb_base->timestamp_ref_ctrl);
|
||||
|
||||
debug("ref ctrl 0x%x\n",
|
||||
readl(&crlapb_base->timestamp_ref_ctrl));
|
||||
|
||||
/* Clear reset of timestamp reg */
|
||||
writel(0, &crlapb_base->rst_timestamp);
|
||||
|
||||
/*
|
||||
* Program freq register in System counter and
|
||||
* enable system counter.
|
||||
*/
|
||||
writel(CONFIG_COUNTER_FREQUENCY,
|
||||
&iou_scntr_secure->base_frequency_id_register);
|
||||
|
||||
debug("counter val 0x%x\n",
|
||||
readl(&iou_scntr_secure->base_frequency_id_register));
|
||||
|
||||
writel(IOU_SCNTRS_CONTROL_EN,
|
||||
&iou_scntr_secure->counter_control_register);
|
||||
|
||||
debug("scntrs control 0x%x\n",
|
||||
readl(&iou_scntr_secure->counter_control_register));
|
||||
debug("timer 0x%llx\n", get_ticks());
|
||||
debug("timer 0x%llx\n", get_ticks());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 versal_net_get_bootmode(void)
|
||||
{
|
||||
u8 bootmode;
|
||||
u32 reg = 0;
|
||||
|
||||
reg = readl(&crp_base->boot_mode_usr);
|
||||
|
||||
if (reg >> BOOT_MODE_ALT_SHIFT)
|
||||
reg >>= BOOT_MODE_ALT_SHIFT;
|
||||
|
||||
bootmode = reg & BOOT_MODES_MASK;
|
||||
|
||||
return bootmode;
|
||||
}
|
||||
|
||||
static int boot_targets_setup(void)
|
||||
{
|
||||
u8 bootmode;
|
||||
struct udevice *dev;
|
||||
int bootseq = -1;
|
||||
int bootseq_len = 0;
|
||||
int env_targets_len = 0;
|
||||
const char *mode = NULL;
|
||||
char *new_targets;
|
||||
char *env_targets;
|
||||
|
||||
bootmode = versal_net_get_bootmode();
|
||||
|
||||
puts("Bootmode: ");
|
||||
switch (bootmode) {
|
||||
case USB_MODE:
|
||||
puts("USB_MODE\n");
|
||||
mode = "usb_dfu0 usb_dfu1";
|
||||
break;
|
||||
case JTAG_MODE:
|
||||
puts("JTAG_MODE\n");
|
||||
mode = "jtag pxe dhcp";
|
||||
break;
|
||||
case QSPI_MODE_24BIT:
|
||||
puts("QSPI_MODE_24\n");
|
||||
if (uclass_get_device_by_name(UCLASS_SPI,
|
||||
"spi@f1030000", &dev)) {
|
||||
debug("QSPI driver for QSPI device is not present\n");
|
||||
break;
|
||||
}
|
||||
mode = "xspi";
|
||||
bootseq = dev_seq(dev);
|
||||
break;
|
||||
case QSPI_MODE_32BIT:
|
||||
puts("QSPI_MODE_32\n");
|
||||
if (uclass_get_device_by_name(UCLASS_SPI,
|
||||
"spi@f1030000", &dev)) {
|
||||
debug("QSPI driver for QSPI device is not present\n");
|
||||
break;
|
||||
}
|
||||
mode = "xspi";
|
||||
bootseq = dev_seq(dev);
|
||||
break;
|
||||
case OSPI_MODE:
|
||||
puts("OSPI_MODE\n");
|
||||
if (uclass_get_device_by_name(UCLASS_SPI,
|
||||
"spi@f1010000", &dev)) {
|
||||
debug("OSPI driver for OSPI device is not present\n");
|
||||
break;
|
||||
}
|
||||
mode = "xspi";
|
||||
bootseq = dev_seq(dev);
|
||||
break;
|
||||
case EMMC_MODE:
|
||||
puts("EMMC_MODE\n");
|
||||
mode = "mmc";
|
||||
bootseq = dev_seq(dev);
|
||||
break;
|
||||
case SELECTMAP_MODE:
|
||||
puts("SELECTMAP_MODE\n");
|
||||
break;
|
||||
case SD_MODE:
|
||||
puts("SD_MODE\n");
|
||||
if (uclass_get_device_by_name(UCLASS_MMC,
|
||||
"mmc@f1040000", &dev)) {
|
||||
debug("SD0 driver for SD0 device is not present\n");
|
||||
break;
|
||||
}
|
||||
debug("mmc0 device found at %p, seq %d\n", dev, dev_seq(dev));
|
||||
|
||||
mode = "mmc";
|
||||
bootseq = dev_seq(dev);
|
||||
break;
|
||||
case SD1_LSHFT_MODE:
|
||||
puts("LVL_SHFT_");
|
||||
fallthrough;
|
||||
case SD_MODE1:
|
||||
puts("SD_MODE1\n");
|
||||
if (uclass_get_device_by_name(UCLASS_MMC,
|
||||
"mmc@f1050000", &dev)) {
|
||||
debug("SD1 driver for SD1 device is not present\n");
|
||||
break;
|
||||
}
|
||||
debug("mmc1 device found at %p, seq %d\n", dev, dev_seq(dev));
|
||||
|
||||
mode = "mmc";
|
||||
bootseq = dev_seq(dev);
|
||||
break;
|
||||
default:
|
||||
printf("Invalid Boot Mode:0x%x\n", bootmode);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode) {
|
||||
if (bootseq >= 0) {
|
||||
bootseq_len = snprintf(NULL, 0, "%i", bootseq);
|
||||
debug("Bootseq len: %x\n", bootseq_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* One terminating char + one byte for space between mode
|
||||
* and default boot_targets
|
||||
*/
|
||||
env_targets = env_get("boot_targets");
|
||||
if (env_targets)
|
||||
env_targets_len = strlen(env_targets);
|
||||
|
||||
new_targets = calloc(1, strlen(mode) + env_targets_len + 2 +
|
||||
bootseq_len);
|
||||
if (!new_targets)
|
||||
return -ENOMEM;
|
||||
|
||||
if (bootseq >= 0)
|
||||
sprintf(new_targets, "%s%x %s", mode, bootseq,
|
||||
env_targets ? env_targets : "");
|
||||
else
|
||||
sprintf(new_targets, "%s %s", mode,
|
||||
env_targets ? env_targets : "");
|
||||
|
||||
env_set("boot_targets", new_targets);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int board_late_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!(gd->flags & GD_FLG_ENV_DEFAULT)) {
|
||||
debug("Saved variables - Skipping\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG))
|
||||
return 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_DISTRO_DEFAULTS)) {
|
||||
ret = boot_targets_setup();
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return board_late_init_xilinx();
|
||||
}
|
||||
|
||||
int dram_init_banksize(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = fdtdec_setup_memory_banksize();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mem_map_fill();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_SYS_MEM_RSVD_FOR_MMU))
|
||||
ret = fdtdec_setup_mem_size_base();
|
||||
else
|
||||
ret = fdtdec_setup_mem_size_base_lowest();
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reset_cpu(void)
|
||||
{
|
||||
}
|
81
board/amd/versal2/cmds.c
Normal file
81
board/amd/versal2/cmds.c
Normal file
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2024, Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Michal Simek <michal.simek@amd.com>
|
||||
*/
|
||||
|
||||
#include <cpu_func.h>
|
||||
#include <command.h>
|
||||
#include <log.h>
|
||||
#include <memalign.h>
|
||||
#include <versalpl.h>
|
||||
#include <vsprintf.h>
|
||||
#include <zynqmp_firmware.h>
|
||||
|
||||
/**
|
||||
* do_versal2_load_pdi - Handle the "versal2 load pdi" command-line command
|
||||
* @cmdtp: Command data struct pointer
|
||||
* @flag: Command flag
|
||||
* @argc: Command-line argument count
|
||||
* @argv: Array of command-line arguments
|
||||
*
|
||||
* Processes the versal2 load pdi command
|
||||
*
|
||||
* Return: return 0 on success, Error value if command fails.
|
||||
* CMD_RET_USAGE incase of incorrect/missing parameters.
|
||||
*/
|
||||
static int do_versal2_load_pdi(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
u32 buf_lo, buf_hi;
|
||||
u32 ret_payload[PAYLOAD_ARG_CNT];
|
||||
ulong addr, *pdi_buf;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if (argc != cmdtp->maxargs) {
|
||||
debug("pdi_load: incorrect parameters passed\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
addr = simple_strtol(argv[1], NULL, 16);
|
||||
if (!addr) {
|
||||
debug("pdi_load: zero pdi_data address\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
len = hextoul(argv[2], NULL);
|
||||
if (!len) {
|
||||
debug("pdi_load: zero size\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
pdi_buf = (ulong *)ALIGN((ulong)addr, ARCH_DMA_MINALIGN);
|
||||
if ((ulong)addr != (ulong)pdi_buf) {
|
||||
memcpy((void *)pdi_buf, (void *)addr, len);
|
||||
debug("Pdi addr:0x%lx aligned to 0x%lx\n",
|
||||
addr, (ulong)pdi_buf);
|
||||
}
|
||||
|
||||
flush_dcache_range((ulong)pdi_buf, (ulong)pdi_buf + len);
|
||||
|
||||
buf_lo = lower_32_bits((ulong)pdi_buf);
|
||||
buf_hi = upper_32_bits((ulong)pdi_buf);
|
||||
|
||||
ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo,
|
||||
buf_hi, 0, ret_payload);
|
||||
if (ret)
|
||||
printf("PDI load failed with err: 0x%08x\n", ret);
|
||||
|
||||
return cmd_process_error(cmdtp, ret);
|
||||
}
|
||||
|
||||
static char versal2_help_text[] =
|
||||
"loadpdi addr len - Load pdi image\n"
|
||||
"load pdi image at ddr address 'addr' with pdi image size 'len'\n"
|
||||
;
|
||||
|
||||
U_BOOT_CMD_WITH_SUBCMDS(versal2, "Versal Gen 2 sub-system", versal2_help_text,
|
||||
U_BOOT_SUBCMD_MKENT(loadpdi, 3, 1,
|
||||
do_versal2_load_pdi));
|
@@ -42,7 +42,7 @@ endif
|
||||
|
||||
config XILINX_OF_BOARD_DTB_ADDR
|
||||
hex "Default DTB pickup address"
|
||||
default 0x1000 if ARCH_VERSAL || ARCH_VERSAL_NET
|
||||
default 0x1000 if ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2
|
||||
default 0x8000 if MICROBLAZE
|
||||
default 0x100000 if ARCH_ZYNQ || ARCH_ZYNQMP
|
||||
default 0x23000000 if TARGET_XILINX_MBV
|
||||
@@ -52,10 +52,10 @@ config XILINX_OF_BOARD_DTB_ADDR
|
||||
|
||||
config BOOT_SCRIPT_OFFSET
|
||||
hex "Boot script offset"
|
||||
depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL || ARCH_VERSAL_NET || MICROBLAZE || TARGET_XILINX_MBV
|
||||
depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2 || MICROBLAZE || TARGET_XILINX_MBV
|
||||
default 0xFC0000 if ARCH_ZYNQ || MICROBLAZE
|
||||
default 0x3E80000 if ARCH_ZYNQMP
|
||||
default 0x7F80000 if ARCH_VERSAL || ARCH_VERSAL_NET
|
||||
default 0x7F80000 if ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2
|
||||
default 0 if TARGET_XILINX_MBV
|
||||
help
|
||||
Specifies distro boot script offset in NAND/QSPI/NOR flash.
|
||||
|
Reference in New Issue
Block a user