X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=board%2Fxilinx%2Fzynqmp%2Fzynqmp.c;h=f15dc5d71522231ed478bf3639747781bf9f59cb;hb=0678941ae54b3f1bbd8024c8d74fb282f0c1b590;hp=44d347ed3bf0e857244ebb2971bf7990db73432e;hpb=cd85bec36d0e0d16fedb00e0c434ed070a9c6b37;p=u-boot diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 44d347ed3b..911cd52e0c 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -1,35 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2014 - 2015 Xilinx, Inc. * Michal Simek - * - * SPDX-License-Identifier: GPL-2.0+ */ #include -#include +#include #include #include +#include +#include #include #include #include +#include #include +#include #include #include +#include +#include +#include DECLARE_GLOBAL_DATA_PTR; +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT) +static struct udevice *watchdog_dev; +#endif + +#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \ + !defined(CONFIG_SPL_BUILD) +static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC; + +static const struct { + u32 id; + u32 ver; + char *name; + bool evexists; +} zynqmp_devices[] = { + { + .id = 0x10, + .name = "3eg", + }, + { + .id = 0x10, + .ver = 0x2c, + .name = "3cg", + }, + { + .id = 0x11, + .name = "2eg", + }, + { + .id = 0x11, + .ver = 0x2c, + .name = "2cg", + }, + { + .id = 0x20, + .name = "5ev", + .evexists = 1, + }, + { + .id = 0x20, + .ver = 0x100, + .name = "5eg", + .evexists = 1, + }, + { + .id = 0x20, + .ver = 0x12c, + .name = "5cg", + }, + { + .id = 0x21, + .name = "4ev", + .evexists = 1, + }, + { + .id = 0x21, + .ver = 0x100, + .name = "4eg", + .evexists = 1, + }, + { + .id = 0x21, + .ver = 0x12c, + .name = "4cg", + }, + { + .id = 0x30, + .name = "7ev", + .evexists = 1, + }, + { + .id = 0x30, + .ver = 0x100, + .name = "7eg", + .evexists = 1, + }, + { + .id = 0x30, + .ver = 0x12c, + .name = "7cg", + }, + { + .id = 0x38, + .name = "9eg", + }, + { + .id = 0x38, + .ver = 0x2c, + .name = "9cg", + }, + { + .id = 0x39, + .name = "6eg", + }, + { + .id = 0x39, + .ver = 0x2c, + .name = "6cg", + }, + { + .id = 0x40, + .name = "11eg", + }, + { /* For testing purpose only */ + .id = 0x50, + .ver = 0x2c, + .name = "15cg", + }, + { + .id = 0x50, + .name = "15eg", + }, + { + .id = 0x58, + .name = "19eg", + }, + { + .id = 0x59, + .name = "17eg", + }, + { + .id = 0x61, + .name = "21dr", + }, + { + .id = 0x63, + .name = "23dr", + }, + { + .id = 0x65, + .name = "25dr", + }, + { + .id = 0x64, + .name = "27dr", + }, + { + .id = 0x60, + .name = "28dr", + }, + { + .id = 0x62, + .name = "29dr", + }, +}; +#endif + +int chip_id(unsigned char id) +{ + struct pt_regs regs; + int val = -EINVAL; + + if (current_el() != 3) { + regs.regs[0] = ZYNQMP_SIP_SVC_CSU_DMA_CHIPID; + regs.regs[1] = 0; + regs.regs[2] = 0; + regs.regs[3] = 0; + + smc_call(®s); + + /* + * 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[1][63:32] = CSU.IDCODE2 register + */ + switch (id) { + case IDCODE: + 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; + val = regs.regs[0]; + break; + case VERSION: + regs.regs[1] = lower_32_bits(regs.regs[1]); + regs.regs[1] &= ZYNQMP_CSU_SILICON_VER_MASK; + val = regs.regs[1]; + break; + case IDCODE2: + regs.regs[1] = lower_32_bits(regs.regs[1]); + regs.regs[1] >>= ZYNQMP_CSU_VERSION_EMPTY_SHIFT; + val = regs.regs[1]; + break; + default: + printf("%s, Invalid Req:0x%x\n", __func__, id); + } + } else { + switch (id) { + case IDCODE: + val = readl(ZYNQMP_CSU_IDCODE_ADDR); + val &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | + ZYNQMP_CSU_IDCODE_SVD_MASK; + val >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT; + break; + case VERSION: + val = readl(ZYNQMP_CSU_VER_ADDR); + val &= ZYNQMP_CSU_SILICON_VER_MASK; + break; + default: + printf("%s, Invalid Req:0x%x\n", __func__, id); + } + } + + return val; +} + +#define ZYNQMP_VERSION_SIZE 9 +#define ZYNQMP_PL_STATUS_BIT 9 +#define ZYNQMP_PL_STATUS_MASK BIT(ZYNQMP_PL_STATUS_BIT) +#define ZYNQMP_CSU_VERSION_MASK ~(ZYNQMP_PL_STATUS_MASK) + +#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \ + !defined(CONFIG_SPL_BUILD) +static char *zynqmp_get_silicon_idcode_name(void) +{ + u32 i, id, ver; + char *buf; + static char name[ZYNQMP_VERSION_SIZE]; + + id = chip_id(IDCODE); + ver = chip_id(IDCODE2); + + for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { + if ((zynqmp_devices[i].id == id) && + (zynqmp_devices[i].ver == (ver & + ZYNQMP_CSU_VERSION_MASK))) { + strncat(name, "zu", 2); + strncat(name, zynqmp_devices[i].name, + ZYNQMP_VERSION_SIZE - 3); + break; + } + } + + if (i >= ARRAY_SIZE(zynqmp_devices)) + return "unknown"; + + if (!zynqmp_devices[i].evexists) + return name; + + if (ver & ZYNQMP_PL_STATUS_MASK) + return name; + + if (strstr(name, "eg") || strstr(name, "ev")) { + buf = strstr(name, "e"); + *buf = '\0'; + } + + return name; +} +#endif + +int board_early_init_f(void) +{ + int ret = 0; +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_CLK_ZYNQMP) + zynqmp_pmufw_version(); +#endif + +#if defined(CONFIG_ZYNQMP_PSU_INIT_ENABLED) + ret = psu_init(); +#endif + +#if defined(CONFIG_WDT) && !defined(CONFIG_SPL_BUILD) + /* bss is not cleared at time when watchdog_reset() is called */ + watchdog_dev = NULL; +#endif + + return ret; +} + 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) { + zynqmppl.name = zynqmp_get_silicon_idcode_name(); + printf("Chip ID:\t%s\n", zynqmppl.name); + fpga_init(); + fpga_add(fpga_xilinx, &zynqmppl); + } +#endif + +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT) + if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) { + puts("Watchdog: Not found!\n"); + } else { + wdt_start(watchdog_dev, 0, 0); + puts("Watchdog: Started\n"); + } +#endif + return 0; } +#ifdef CONFIG_WATCHDOG +/* Called by macro WATCHDOG_RESET */ +void watchdog_reset(void) +{ +# if !defined(CONFIG_SPL_BUILD) + static ulong next_reset; + ulong now; + + if (!watchdog_dev) + return; + + now = timer_get_us(); + + /* Do not reset the watchdog too often */ + if (now > next_reset) { + wdt_reset(watchdog_dev); + next_reset = now + 1000; + } +# endif +} +#endif + int board_early_init_r(void) { u32 val; - if (current_el() == 3) { + if (current_el() != 3) + return 0; + + val = readl(&crlapb_base->timestamp_ref_ctrl); + val &= ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT; + + if (!val) { val = readl(&crlapb_base->timestamp_ref_ctrl); val |= ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT; writel(val, &crlapb_base->timestamp_ref_ctrl); @@ -41,77 +366,180 @@ int board_early_init_r(void) 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; } -int dram_init(void) +unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc, + char * const argv[]) { - gd->ram_size = CONFIG_SYS_SDRAM_SIZE; + int ret = 0; + + if (current_el() > 1) { + smp_kick_all_cpus(); + dcache_disable(); + armv8_switch_to_el1(0x0, 0, 0, 0, (unsigned long)entry, + ES_TO_AARCH64); + } else { + printf("FAIL: current EL is not above EL1\n"); + ret = EINVAL; + } + return ret; +} + +#if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE) +int dram_init_banksize(void) +{ + int ret; + + ret = fdtdec_setup_memory_banksize(); + if (ret) + return ret; + + mem_map_fill(); return 0; } -void reset_cpu(ulong addr) +int dram_init(void) { + if (fdtdec_setup_memory_size() != 0) + return -EINVAL; + + return 0; +} +#else +int dram_init_banksize(void) +{ +#if defined(CONFIG_NR_DRAM_BANKS) + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; + gd->bd->bi_dram[0].size = get_effective_memsize(); +#endif + + mem_map_fill(); + + return 0; } -#ifdef CONFIG_SCSI_AHCI_PLAT -void scsi_init(void) +int dram_init(void) { - ahci_init((void __iomem *)ZYNQMP_SATA_BASEADDR); - scsi_scan(1); + gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, + 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; + char *env_targets; + int ret; + + if (!(gd->flags & GD_FLG_ENV_DEFAULT)) { + debug("Saved variables - Skipping\n"); + return 0; + } + + ret = zynqmp_mmio_read((ulong)&crlapb_base->boot_mode, ®); + if (ret) + return -EINVAL; + + if (reg >> BOOT_MODE_ALT_SHIFT) + reg >>= BOOT_MODE_ALT_SHIFT; - reg = readl(&crlapb_base->boot_mode); bootmode = reg & BOOT_MODES_MASK; puts("Bootmode: "); switch (bootmode) { + case USB_MODE: + puts("USB_MODE\n"); + mode = "usb"; + env_set("modeboot", "usb_dfu_spl"); + break; case JTAG_MODE: puts("JTAG_MODE\n"); - setenv("modeboot", "jtagboot"); + mode = "pxe dhcp"; + env_set("modeboot", "jtagboot"); break; case QSPI_MODE_24BIT: case QSPI_MODE_32BIT: - setenv("modeboot", "qspiboot"); + mode = "qspi0"; puts("QSPI_MODE\n"); + env_set("modeboot", "qspiboot"); break; case EMMC_MODE: puts("EMMC_MODE\n"); - setenv("modeboot", "sdboot"); + mode = "mmc0"; + env_set("modeboot", "emmcboot"); break; case SD_MODE: puts("SD_MODE\n"); - setenv("modeboot", "sdboot"); + mode = "mmc0"; + env_set("modeboot", "sdboot"); 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) - setenv("sdbootdev", "1"); + mode = "mmc1"; + env_set("sdbootdev", "1"); +#else + mode = "mmc0"; #endif - setenv("modeboot", "sdboot"); + env_set("modeboot", "sdboot"); break; case NAND_MODE: puts("NAND_MODE\n"); - setenv("modeboot", "nandboot"); + mode = "nand0"; + env_set("modeboot", "nandboot"); 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 + */ + env_targets = env_get("boot_targets"); + if (env_targets) { + new_targets = calloc(1, strlen(mode) + + strlen(env_targets) + 2); + sprintf(new_targets, "%s %s", mode, env_targets); + } else { + new_targets = calloc(1, strlen(mode) + 2); + sprintf(new_targets, "%s", mode); + } + + env_set("boot_targets", new_targets); + return 0; } @@ -122,22 +550,42 @@ int checkboard(void) } #ifdef CONFIG_USB_DWC3 -static struct dwc3_device dwc3_device_data = { +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, }; -int usb_gadget_handle_interrupts(void) +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(0); + dwc3_uboot_handle_interrupt(index); return 0; } int board_usb_init(int index, enum usb_init_type init) { - return dwc3_uboot_init(&dwc3_device_data); + 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)