u-boot-brain/board/xilinx/zynqmp/zynqmp.c
Michal Simek fb4000e871 arm64: zynqmp: Check pmufw version
If PMUFW version is not v0.3 then panic.
ZynqMP switch to CCF based clock driver which requires
PMUFW to be present at certain version.
This patch ensure that you use correct and tested PMUFW
binary.

Signed-off-by: Michal Simek <michal.simek@xilinx.com>
2017-06-20 16:42:13 +02:00

344 lines
6.4 KiB
C

/*
* (C) Copyright 2014 - 2015 Xilinx, Inc.
* Michal Simek <michal.simek@xilinx.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <sata.h>
#include <ahci.h>
#include <scsi.h>
#include <malloc.h>
#include <asm/arch/clk.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sys_proto.h>
#include <asm/io.h>
#include <usb.h>
#include <dwc3-uboot.h>
#include <zynqmppl.h>
#include <i2c.h>
#include <g_dnl.h>
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
!defined(CONFIG_SPL_BUILD)
static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC;
static const struct {
uint32_t id;
char *name;
} zynqmp_devices[] = {
{
.id = 0x10,
.name = "3eg",
},
{
.id = 0x11,
.name = "2eg",
},
{
.id = 0x20,
.name = "5ev",
},
{
.id = 0x21,
.name = "4ev",
},
{
.id = 0x30,
.name = "7ev",
},
{
.id = 0x38,
.name = "9eg",
},
{
.id = 0x39,
.name = "6eg",
},
{
.id = 0x40,
.name = "11eg",
},
{
.id = 0x50,
.name = "15eg",
},
{
.id = 0x58,
.name = "19eg",
},
{
.id = 0x59,
.name = "17eg",
},
};
static int chip_id(void)
{
struct pt_regs regs;
regs.regs[0] = ZYNQMP_SIP_SVC_CSU_DMA_CHIPID;
regs.regs[1] = 0;
regs.regs[2] = 0;
regs.regs[3] = 0;
smc_call(&regs);
/*
* SMC returns:
* regs[0][31:0] = status of the operation
* regs[0][63:32] = CSU.IDCODE register
* regs[1][31:0] = CSU.version register
*/
regs.regs[0] = upper_32_bits(regs.regs[0]);
regs.regs[0] &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
ZYNQMP_CSU_IDCODE_SVD_MASK;
regs.regs[0] >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
return regs.regs[0];
}
static char *zynqmp_get_silicon_idcode_name(void)
{
uint32_t i, id;
id = chip_id();
for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
if (zynqmp_devices[i].id == id)
return zynqmp_devices[i].name;
}
return "unknown";
}
#endif
int board_early_init_f(void)
{
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_CLK_ZYNQMP)
zynqmp_pmufw_version();
#endif
return 0;
}
#define ZYNQMP_VERSION_SIZE 9
int board_init(void)
{
printf("EL Level:\tEL%d\n", current_el());
#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
!defined(CONFIG_SPL_BUILD) || (defined(CONFIG_SPL_FPGA_SUPPORT) && \
defined(CONFIG_SPL_BUILD))
if (current_el() != 3) {
static char version[ZYNQMP_VERSION_SIZE];
strncat(version, "xczu", ZYNQMP_VERSION_SIZE);
zynqmppl.name = strncat(version,
zynqmp_get_silicon_idcode_name(),
ZYNQMP_VERSION_SIZE);
printf("Chip ID:\t%s\n", zynqmppl.name);
fpga_init();
fpga_add(fpga_xilinx, &zynqmppl);
}
#endif
return 0;
}
int board_early_init_r(void)
{
u32 val;
if (current_el() == 3) {
val = readl(&crlapb_base->timestamp_ref_ctrl);
val |= ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT;
writel(val, &crlapb_base->timestamp_ref_ctrl);
/* Program freq register in System counter */
writel(zynqmp_get_system_timer_freq(),
&iou_scntr_secure->base_frequency_id_register);
/* And enable system counter */
writel(ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_EN,
&iou_scntr_secure->counter_control_register);
}
/* Program freq register in System counter and enable system counter */
writel(gd->cpu_clk, &iou_scntr->base_frequency_id_register);
writel(ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_HDBG |
ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_EN,
&iou_scntr->counter_control_register);
return 0;
}
int zynq_board_read_rom_ethaddr(unsigned char *ethaddr)
{
#if defined(CONFIG_ZYNQ_GEM_EEPROM_ADDR) && \
defined(CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET) && \
defined(CONFIG_ZYNQ_EEPROM_BUS)
i2c_set_bus_num(CONFIG_ZYNQ_EEPROM_BUS);
if (eeprom_read(CONFIG_ZYNQ_GEM_EEPROM_ADDR,
CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET,
ethaddr, 6))
printf("I2C EEPROM MAC address read failed\n");
#endif
return 0;
}
#if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE)
int dram_init_banksize(void)
{
fdtdec_setup_memory_banksize();
return 0;
}
int dram_init(void)
{
if (fdtdec_setup_memory_size() != 0)
return -EINVAL;
return 0;
}
#else
int dram_init(void)
{
gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
return 0;
}
#endif
void reset_cpu(ulong addr)
{
}
int board_late_init(void)
{
u32 reg = 0;
u8 bootmode;
const char *mode;
char *new_targets;
if (!(gd->flags & GD_FLG_ENV_DEFAULT)) {
debug("Saved variables - Skipping\n");
return 0;
}
reg = readl(&crlapb_base->boot_mode);
if (reg >> BOOT_MODE_ALT_SHIFT)
reg >>= BOOT_MODE_ALT_SHIFT;
bootmode = reg & BOOT_MODES_MASK;
puts("Bootmode: ");
switch (bootmode) {
case USB_MODE:
puts("USB_MODE\n");
mode = "usb";
break;
case JTAG_MODE:
puts("JTAG_MODE\n");
mode = "pxe dhcp";
break;
case QSPI_MODE_24BIT:
case QSPI_MODE_32BIT:
mode = "qspi0";
puts("QSPI_MODE\n");
break;
case EMMC_MODE:
puts("EMMC_MODE\n");
mode = "mmc0";
break;
case SD_MODE:
puts("SD_MODE\n");
mode = "mmc0";
break;
case SD1_LSHFT_MODE:
puts("LVL_SHFT_");
/* fall through */
case SD_MODE1:
puts("SD_MODE1\n");
#if defined(CONFIG_ZYNQ_SDHCI0) && defined(CONFIG_ZYNQ_SDHCI1)
mode = "mmc1";
#else
mode = "mmc0";
#endif
break;
case NAND_MODE:
puts("NAND_MODE\n");
mode = "nand0";
break;
default:
mode = "";
printf("Invalid Boot Mode:0x%x\n", bootmode);
break;
}
/*
* One terminating char + one byte for space between mode
* and default boot_targets
*/
new_targets = calloc(1, strlen(mode) +
strlen(getenv("boot_targets")) + 2);
sprintf(new_targets, "%s %s", mode, getenv("boot_targets"));
setenv("boot_targets", new_targets);
return 0;
}
int checkboard(void)
{
puts("Board: Xilinx ZynqMP\n");
return 0;
}
#ifdef CONFIG_USB_DWC3
static struct dwc3_device dwc3_device_data0 = {
.maximum_speed = USB_SPEED_HIGH,
.base = ZYNQMP_USB0_XHCI_BASEADDR,
.dr_mode = USB_DR_MODE_PERIPHERAL,
.index = 0,
};
static struct dwc3_device dwc3_device_data1 = {
.maximum_speed = USB_SPEED_HIGH,
.base = ZYNQMP_USB1_XHCI_BASEADDR,
.dr_mode = USB_DR_MODE_PERIPHERAL,
.index = 1,
};
int usb_gadget_handle_interrupts(int index)
{
dwc3_uboot_handle_interrupt(index);
return 0;
}
int board_usb_init(int index, enum usb_init_type init)
{
debug("%s: index %x\n", __func__, index);
#if defined(CONFIG_USB_GADGET_DOWNLOAD)
g_dnl_set_serialnumber(CONFIG_SYS_CONFIG_NAME);
#endif
switch (index) {
case 0:
return dwc3_uboot_init(&dwc3_device_data0);
case 1:
return dwc3_uboot_init(&dwc3_device_data1);
};
return -1;
}
int board_usb_cleanup(int index, enum usb_init_type init)
{
dwc3_uboot_exit(index);
return 0;
}
#endif