X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=board%2Fxilinx%2Fzynqmp%2Fzynqmp.c;h=13c404b6ef0882fea2a78b15fcc819b5920e1d0f;hb=9450ab2ba8d720bd9f73bccc0af2e2b5a2c2aaf1;hp=3849b5885dfe4b4631c6cc2a5bf0fa8b85850b23;hpb=1622559066d890f1b7622be0ede8a5d64de66ef3;p=platform%2Fkernel%2Fu-boot.git diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 3849b58..13c404b 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,14 @@ #include #include #include +#include #include #include #include +#include #include +#include +#include #include #include #include @@ -22,46 +25,116 @@ 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", + .evexists = 1, }, { .id = 0x21, .name = "4ev", + .evexists = 1, + }, + { + .id = 0x21, + .ver = 0x100, + .name = "4eg", + .evexists = 1, + }, + { + .id = 0x21, + .ver = 0x12c, + .name = "4cg", + .evexists = 1, }, { .id = 0x30, .name = "7ev", + .evexists = 1, + }, + { + .id = 0x30, + .ver = 0x100, + .name = "7eg", + .evexists = 1, + }, + { + .id = 0x30, + .ver = 0x12c, + .name = "7cg", + .evexists = 1, }, { .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 +147,189 @@ 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; - - smc_call(®s); + int val = -EINVAL; - /* - * 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_IPDIS_VCU_BIT 8 +#define ZYNQMP_PL_STATUS_MASK BIT(ZYNQMP_PL_STATUS_BIT) +#define ZYNQMP_CSU_VERSION_MASK ~(ZYNQMP_PL_STATUS_MASK) +#define ZYNQMP_CSU_VCUDIS_VER_MASK ZYNQMP_CSU_VERSION_MASK & \ + ~BIT(ZYNQMP_IPDIS_VCU_BIT) +#define MAX_VARIANTS_EV 3 + +#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, j; + 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) { + if (zynqmp_devices[i].evexists && + !(ver & ZYNQMP_PL_STATUS_MASK)) + break; + if (zynqmp_devices[i].ver == (ver & + ZYNQMP_CSU_VERSION_MASK)) + break; + } } - return "unknown"; + + if (i >= ARRAY_SIZE(zynqmp_devices)) + return "unknown"; + + strncat(name, "zu", 2); + if (!zynqmp_devices[i].evexists || + (ver & ZYNQMP_PL_STATUS_MASK)) { + strncat(name, zynqmp_devices[i].name, + ZYNQMP_VERSION_SIZE - 3); + return name; + } + + /* + * Here we are means, PL not powered up and ev variant + * exists. So, we need to ignore VCU disable bit(8) in + * version and findout if its CG or EG/EV variant. + */ + for (j = 0; j < MAX_VARIANTS_EV; j++, i++) { + if ((zynqmp_devices[i].ver & ~BIT(ZYNQMP_IPDIS_VCU_BIT)) == + (ver & ZYNQMP_CSU_VCUDIS_VER_MASK)) { + strncat(name, zynqmp_devices[i].name, + ZYNQMP_VERSION_SIZE - 3); + break; + } + } + + if (j >= MAX_VARIANTS_EV) + return "unknown"; + + 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) + u32 pm_api_version; + + pm_api_version = zynqmp_pmufw_version(); + printf("PMUFW:\tv%d.%d\n", + pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT, + pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK); + + if (pm_api_version < ZYNQMP_PM_VERSION) + panic("PMUFW version error. Expected: v%d.%d\n", + ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR); +#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 +339,62 @@ 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_by_seq(UCLASS_WDT, 0, &watchdog_dev)) { + debug("Watchdog: Not found by seq!\n"); + if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) { + puts("Watchdog: Not found!\n"); + return 0; + } + } + + 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 +406,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,25 +425,61 @@ int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) return 0; } +unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc, + char * const argv[]) +{ + 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) { - fdtdec_setup_memory_banksize(); + int ret; + + ret = fdtdec_setup_memory_banksize(); + if (ret) + return ret; + + mem_map_fill(); return 0; } int dram_init(void) { - if (fdtdec_setup_memory_size() != 0) + if (fdtdec_setup_mem_size_base() != 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; +} + 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; } @@ -207,19 +489,73 @@ void reset_cpu(ulong addr) { } +static const struct { + u32 bit; + const char *name; +} reset_reasons[] = { + { RESET_REASON_DEBUG_SYS, "DEBUG" }, + { RESET_REASON_SOFT, "SOFT" }, + { RESET_REASON_SRST, "SRST" }, + { RESET_REASON_PSONLY, "PS-ONLY" }, + { RESET_REASON_PMU, "PMU" }, + { RESET_REASON_INTERNAL, "INTERNAL" }, + { RESET_REASON_EXTERNAL, "EXTERNAL" }, + {} +}; + +static u32 reset_reason(void) +{ + u32 ret; + int i; + const char *reason = NULL; + + ret = readl(&crlapb_base->reset_reason); + + puts("Reset reason:\t"); + + for (i = 0; i < ARRAY_SIZE(reset_reasons); i++) { + if (ret & reset_reasons[i].bit) { + reason = reset_reasons[i].name; + printf("%s ", reset_reasons[i].name); + break; + } + } + + puts("\n"); + + env_set("reset_reason", reason); + + writel(~0, &crlapb_base->reset_reason); + + return ret; +} + int board_late_init(void) { u32 reg = 0; u8 bootmode; + struct udevice *dev; + int bootseq = -1; + int bootseq_len = 0; + int env_targets_len = 0; const char *mode; char *new_targets; + char *env_targets; + int ret; + +#if defined(CONFIG_USB_ETHER) && !defined(CONFIG_USB_GADGET_DOWNLOAD) + usb_ether_init(); +#endif 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; @@ -230,38 +566,57 @@ 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"; + if (uclass_get_device_by_name(UCLASS_MMC, + "sdhci@ff160000", &dev)) { + puts("Boot from SD0 but without SD0 enabled!\n"); + return -1; + } + debug("mmc0 device found at %p, seq %d\n", dev, dev->seq); + + mode = "mmc"; + bootseq = dev->seq; + 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"; -#else - mode = "mmc0"; -#endif + if (uclass_get_device_by_name(UCLASS_MMC, + "sdhci@ff170000", &dev)) { + puts("Boot from SD1 but without SD1 enabled!\n"); + return -1; + } + debug("mmc1 device found at %p, seq %d\n", dev, dev->seq); + + mode = "mmc"; + bootseq = dev->seq; + env_set("modeboot", "sdboot"); break; case NAND_MODE: puts("NAND_MODE\n"); mode = "nand0"; + env_set("modeboot", "nandboot"); break; default: mode = ""; @@ -269,67 +624,40 @@ int board_late_init(void) break; } + 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 */ - new_targets = calloc(1, strlen(mode) + - strlen(getenv("boot_targets")) + 2); + env_targets = env_get("boot_targets"); + if (env_targets) + env_targets_len = strlen(env_targets); - sprintf(new_targets, "%s %s", mode, getenv("boot_targets")); - setenv("boot_targets", new_targets); + new_targets = calloc(1, strlen(mode) + env_targets_len + 2 + + bootseq_len); + if (!new_targets) + return -ENOMEM; - return 0; -} + 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 : ""); -int checkboard(void) -{ - puts("Board: Xilinx ZynqMP\n"); - return 0; -} + env_set("boot_targets", new_targets); -#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, -}; + reset_reason(); -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) +int checkboard(void) { - dwc3_uboot_exit(index); + puts("Board: Xilinx ZynqMP\n"); return 0; } -#endif