X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=board%2Fxilinx%2Fzynqmp%2Fzynqmp.c;h=911cd52e0c40c51f8820bccff1ffcdc1b70755e3;hb=0678941ae54b3f1bbd8024c8d74fb282f0c1b590;hp=cef1f6a13aee00adc48b0d0781ad5273fa14c8ba;hpb=2d221489df021393654805536be7effcb9d39702;p=u-boot diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index cef1f6a13a..911cd52e0c 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2014 - 2015 Xilinx, Inc. * Michal Simek - * - * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -10,10 +9,13 @@ #include #include #include +#include #include #include #include +#include #include +#include #include #include #include @@ -22,46 +24,113 @@ 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 { - uint32_t id; + 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", @@ -74,46 +143,157 @@ static const struct { .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 -static int chip_id(void) +int chip_id(unsigned char id) { 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; + int val = -EINVAL; - 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.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; + 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 regs.regs[0]; + 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) { - uint32_t i, id; + u32 i, id, ver; + char *buf; + static char name[ZYNQMP_VERSION_SIZE]; + + id = chip_id(IDCODE); + ver = chip_id(IDCODE2); - id = chip_id(); for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { - if (zynqmp_devices[i].id == id) - return zynqmp_devices[i].name; + 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; + } } - return "unknown"; + + 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 -#define ZYNQMP_VERSION_SIZE 9 +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) { @@ -123,26 +303,58 @@ int board_init(void) !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); + 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); @@ -154,12 +366,6 @@ 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; } @@ -179,129 +385,61 @@ int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) return 0; } -#if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE) -/* - * fdt_get_reg - Fill buffer by information from DT - */ -static phys_size_t fdt_get_reg(const void *fdt, int nodeoffset, void *buf, - const u32 *cell, int n) +unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc, + char * const argv[]) { - int i = 0, b, banks; - int parent_offset = fdt_parent_offset(fdt, nodeoffset); - int address_cells = fdt_address_cells(fdt, parent_offset); - int size_cells = fdt_size_cells(fdt, parent_offset); - char *p = buf; - u64 val; - u64 vals; - - debug("%s: addr_cells=%x, size_cell=%x, buf=%p, cell=%p\n", - __func__, address_cells, size_cells, buf, cell); - - /* Check memory bank setup */ - banks = n % (address_cells + size_cells); - if (banks) - panic("Incorrect memory setup cells=%d, ac=%d, sc=%d\n", - n, address_cells, size_cells); - - banks = n / (address_cells + size_cells); - - for (b = 0; b < banks; b++) { - debug("%s: Bank #%d:\n", __func__, b); - if (address_cells == 2) { - val = cell[i + 1]; - val <<= 32; - val |= cell[i]; - val = fdt64_to_cpu(val); - debug("%s: addr64=%llx, ptr=%p, cell=%p\n", - __func__, val, p, &cell[i]); - *(phys_addr_t *)p = val; - } else { - debug("%s: addr32=%x, ptr=%p\n", - __func__, fdt32_to_cpu(cell[i]), p); - *(phys_addr_t *)p = fdt32_to_cpu(cell[i]); - } - p += sizeof(phys_addr_t); - i += address_cells; - - debug("%s: pa=%p, i=%x, size=%zu\n", __func__, p, i, - sizeof(phys_addr_t)); - - if (size_cells == 2) { - vals = cell[i + 1]; - vals <<= 32; - vals |= cell[i]; - vals = fdt64_to_cpu(vals); - - debug("%s: size64=%llx, ptr=%p, cell=%p\n", - __func__, vals, p, &cell[i]); - *(phys_size_t *)p = vals; - } else { - debug("%s: size32=%x, ptr=%p\n", - __func__, fdt32_to_cpu(cell[i]), p); - *(phys_size_t *)p = fdt32_to_cpu(cell[i]); - } - p += sizeof(phys_size_t); - i += size_cells; - - debug("%s: ps=%p, i=%x, size=%zu\n", - __func__, p, i, sizeof(phys_size_t)); + 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 the first address size */ - return *(phys_size_t *)((char *)buf + sizeof(phys_addr_t)); + return ret; } -#define FDT_REG_SIZE sizeof(u32) -/* Temp location for sharing data for storing */ -/* Up to 64-bit address + 64-bit size */ -static u8 tmp[CONFIG_NR_DRAM_BANKS * 16]; - -void dram_init_banksize(void) +#if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE) +int dram_init_banksize(void) { - int bank; + int ret; - memcpy(&gd->bd->bi_dram[0], &tmp, sizeof(tmp)); + ret = fdtdec_setup_memory_banksize(); + if (ret) + return ret; - for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { - debug("Bank #%d: start %llx\n", bank, - (unsigned long long)gd->bd->bi_dram[bank].start); - debug("Bank #%d: size %llx\n", bank, - (unsigned long long)gd->bd->bi_dram[bank].size); - } + mem_map_fill(); + + return 0; } int dram_init(void) { - int node, len; - const void *blob = gd->fdt_blob; - const u32 *cell; - - memset(&tmp, 0, sizeof(tmp)); - - /* find or create "/memory" node. */ - node = fdt_subnode_offset(blob, 0, "memory"); - if (node < 0) { - printf("%s: Can't get memory node\n", __func__); - return node; - } - - /* Get pointer to cells and lenght of it */ - cell = fdt_getprop(blob, node, "reg", &len); - if (!cell) { - printf("%s: Can't get reg property\n", __func__); - return -1; - } + if (fdtdec_setup_memory_size() != 0) + return -EINVAL; - gd->ram_size = fdt_get_reg(blob, node, &tmp, cell, len / FDT_REG_SIZE); + 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 - debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size); + mem_map_fill(); return 0; } -#else + int dram_init(void) { - gd->ram_size = CONFIG_SYS_SDRAM_SIZE; + gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, + CONFIG_SYS_SDRAM_SIZE); return 0; } @@ -311,30 +449,24 @@ void reset_cpu(ulong addr) { } -#ifdef CONFIG_SCSI_AHCI_PLAT -void scsi_init(void) -{ -#if defined(CONFIG_SATA_CEVA) - init_sata(0); -#endif - ahci_init((void __iomem *)ZYNQMP_SATA_BASEADDR); - scsi_scan(1); -} -#endif - 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; } - reg = readl(&crlapb_base->boot_mode); + ret = zynqmp_mmio_read((ulong)&crlapb_base->boot_mode, ®); + if (ret) + return -EINVAL; + if (reg >> BOOT_MODE_ALT_SHIFT) reg >>= BOOT_MODE_ALT_SHIFT; @@ -345,23 +477,28 @@ int board_late_init(void) 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: puts("SD_MODE\n"); mode = "mmc0"; + env_set("modeboot", "sdboot"); break; case SD1_LSHFT_MODE: puts("LVL_SHFT_"); @@ -370,13 +507,16 @@ int board_late_init(void) 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 = ""; @@ -388,11 +528,17 @@ int board_late_init(void) * One terminating char + one byte for space between mode * and default boot_targets */ - new_targets = calloc(1, strlen(mode) + - strlen(getenv("boot_targets")) + 2); + 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); + } - sprintf(new_targets, "%s %s", mode, getenv("boot_targets")); - setenv("boot_targets", new_targets); + env_set("boot_targets", new_targets); return 0; }