X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=board%2Fxilinx%2Fzynqmp%2Fzynqmp.c;h=f15dc5d71522231ed478bf3639747781bf9f59cb;hb=0678941ae54b3f1bbd8024c8d74fb282f0c1b590;hp=e38948426d7067b9cd455c44686260f110fe73b1;hpb=16247d28d5e50fca8b2e11b5e1804524bca83361;p=u-boot diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index e38948426d..911cd52e0c 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -1,94 +1,596 @@ +// 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) + return 0; + val = readl(&crlapb_base->timestamp_ref_ctrl); - val |= ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT; - writel(val, &crlapb_base->timestamp_ref_ctrl); + val &= ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT; - /* 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); + if (!val) { + 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); + } return 0; } -int dram_init(void) +int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) { - gd->ram_size = CONFIG_SYS_SDRAM_SIZE; +#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 timer_init(void) +unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc, + char * const argv[]) { - return 0; + 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; } -void reset_cpu(ulong addr) +#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; } -#ifdef CONFIG_CMD_MMC -int board_mmc_init(bd_t *bd) +int dram_init(void) { - int ret = 0; - - u32 ver = zynqmp_get_silicon_version(); + if (fdtdec_setup_memory_size() != 0) + return -EINVAL; - if (ver != ZYNQMP_CSU_VERSION_VELOCE) { -#if defined(CONFIG_ZYNQ_SDHCI) -# if defined(CONFIG_ZYNQ_SDHCI0) - ret = zynq_sdhci_init(ZYNQ_SDHCI_BASEADDR0); -# endif -# if defined(CONFIG_ZYNQ_SDHCI1) - ret |= zynq_sdhci_init(ZYNQ_SDHCI_BASEADDR1); -# endif + 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 - } - return ret; + mem_map_fill(); + + return 0; +} + +int dram_init(void) +{ + 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"); + mode = "pxe dhcp"; + env_set("modeboot", "jtagboot"); + break; + case QSPI_MODE_24BIT: + case QSPI_MODE_32BIT: + mode = "qspi0"; + puts("QSPI_MODE\n"); + env_set("modeboot", "qspiboot"); + break; + case EMMC_MODE: + puts("EMMC_MODE\n"); + mode = "mmc0"; + env_set("modeboot", "emmcboot"); + break; case SD_MODE: - setenv("modeboot", "sdboot"); + puts("SD_MODE\n"); + 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) + mode = "mmc1"; + env_set("sdbootdev", "1"); +#else + mode = "mmc0"; +#endif + env_set("modeboot", "sdboot"); + break; + case NAND_MODE: + puts("NAND_MODE\n"); + 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; +} + +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