Merge branch 'next'
[oweals/u-boot.git] / board / xilinx / zynqmp / zynqmp.c
index 080fb59ef7bdaa458cc7d2ad833a846f06a85066..3c92b1a5825f5a422770f60b617dd56683928997 100644 (file)
@@ -5,6 +5,10 @@
  */
 
 #include <common.h>
+#include <cpu_func.h>
+#include <debug_uart.h>
+#include <env.h>
+#include <init.h>
 #include <sata.h>
 #include <ahci.h>
 #include <scsi.h>
 #include <usb.h>
 #include <dwc3-uboot.h>
 #include <zynqmppl.h>
-#include <i2c.h>
+#include <zynqmp_firmware.h>
 #include <g_dnl.h>
+#include <linux/sizes.h>
 
-DECLARE_GLOBAL_DATA_PTR;
+#include "pm_cfg_obj.h"
 
-#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
-static struct udevice *watchdog_dev;
-#endif
+DECLARE_GLOBAL_DATA_PTR;
 
 #if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
     !defined(CONFIG_SPL_BUILD)
@@ -72,6 +75,7 @@ static const struct {
                .id = 0x20,
                .ver = 0x12c,
                .name = "5cg",
+               .evexists = 1,
        },
        {
                .id = 0x21,
@@ -88,6 +92,7 @@ static const struct {
                .id = 0x21,
                .ver = 0x12c,
                .name = "4cg",
+               .evexists = 1,
        },
        {
                .id = 0x30,
@@ -104,6 +109,7 @@ static const struct {
                .id = 0x30,
                .ver = 0x12c,
                .name = "7cg",
+               .evexists = 1,
        },
        {
                .id = 0x38,
@@ -168,6 +174,18 @@ static const struct {
                .id = 0x62,
                .name = "29dr",
        },
+       {
+               .id = 0x66,
+               .name = "39dr",
+       },
+       {
+               .id = 0x7b,
+               .name = "48dr",
+       },
+       {
+               .id = 0x7e,
+               .name = "49dr",
+       },
 };
 #endif
 
@@ -234,14 +252,18 @@ int chip_id(unsigned char id)
 
 #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)
 {
-       u32 i, id, ver;
+       u32 i, id, ver, j;
        char *buf;
        static char name[ZYNQMP_VERSION_SIZE];
 
@@ -249,24 +271,43 @@ static char *zynqmp_get_silicon_idcode_name(void)
        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 (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;
                }
        }
 
        if (i >= ARRAY_SIZE(zynqmp_devices))
                return "unknown";
 
-       if (!zynqmp_devices[i].evexists)
+       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;
+       }
 
-       if (ver & ZYNQMP_PL_STATUS_MASK)
-               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");
@@ -279,25 +320,54 @@ static char *zynqmp_get_silicon_idcode_name(void)
 
 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)
+       int ret;
+
        ret = psu_init();
+       if (ret)
+               return ret;
+
+       /* Delay is required for clocks to be propagated */
+       udelay(1000000);
 #endif
 
-#if defined(CONFIG_WDT) && !defined(CONFIG_SPL_BUILD)
-       /* bss is not cleared at time when watchdog_reset() is called */
-       watchdog_dev = NULL;
+#ifdef CONFIG_DEBUG_UART
+       /* Uart debug for sure */
+       debug_uart_init();
+       puts("Debug uart enabled\n"); /* or printch() */
 #endif
 
-       return ret;
+       return 0;
+}
+
+static int multi_boot(void)
+{
+       u32 multiboot;
+
+       multiboot = readl(&csu_base->multi_boot);
+
+       printf("Multiboot:\t%x\n", multiboot);
+
+       return 0;
 }
 
 int board_init(void)
 {
+#if defined(CONFIG_ZYNQMP_FIRMWARE)
+       struct udevice *dev;
+
+       uclass_get_device_by_name(UCLASS_FIRMWARE, "zynqmp-power", &dev);
+       if (!dev)
+               panic("PMU Firmware device not found - Enable it");
+#endif
+
+#if defined(CONFIG_SPL_BUILD)
+       /* Check *at build time* if the filename is an non-empty string */
+       if (sizeof(CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE) > 1)
+               zynqmp_pmufw_load_config_object(zynqmp_pm_cfg_obj,
+                                               zynqmp_pm_cfg_obj_size);
+#endif
+
        printf("EL Level:\tEL%d\n", current_el());
 
 #if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
@@ -311,40 +381,12 @@ int board_init(void)
        }
 #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
+       if (current_el() == 3)
+               multi_boot();
 
        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;
@@ -370,22 +412,6 @@ int board_early_init_r(void)
        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;
-}
-
 unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
                         char * const argv[])
 {
@@ -419,7 +445,7 @@ int dram_init_banksize(void)
 
 int dram_init(void)
 {
-       if (fdtdec_setup_memory_size() != 0)
+       if (fdtdec_setup_mem_size_base() != 0)
                return -EINVAL;
 
        return 0;
@@ -450,6 +476,7 @@ void reset_cpu(ulong addr)
 {
 }
 
+#if defined(CONFIG_BOARD_LATE_INIT)
 static const struct {
        u32 bit;
        const char *name;
@@ -464,18 +491,20 @@ static const struct {
        {}
 };
 
-static u32 reset_reason(void)
+static int reset_reason(void)
 {
-       u32 ret;
-       int i;
+       u32 reg;
+       int i, ret;
        const char *reason = NULL;
 
-       ret = readl(&crlapb_base->reset_reason);
+       ret = zynqmp_mmio_read((ulong)&crlapb_base->reset_reason, &reg);
+       if (ret)
+               return -EINVAL;
 
        puts("Reset reason:\t");
 
        for (i = 0; i < ARRAY_SIZE(reset_reasons); i++) {
-               if (ret & reset_reasons[i].bit) {
+               if (reg & reset_reasons[i].bit) {
                        reason = reset_reasons[i].name;
                        printf("%s ", reset_reasons[i].name);
                        break;
@@ -486,11 +515,43 @@ static u32 reset_reason(void)
 
        env_set("reset_reason", reason);
 
-       writel(~0, &crlapb_base->reset_reason);
+       ret = zynqmp_mmio_write((ulong)&crlapb_base->reset_reason, ~0, ~0);
+       if (ret)
+               return -EINVAL;
 
        return ret;
 }
 
+static int set_fdtfile(void)
+{
+       char *compatible, *fdtfile;
+       const char *suffix = ".dtb";
+       const char *vendor = "xilinx/";
+
+       if (env_get("fdtfile"))
+               return 0;
+
+       compatible = (char *)fdt_getprop(gd->fdt_blob, 0, "compatible", NULL);
+       if (compatible) {
+               debug("Compatible: %s\n", compatible);
+
+               /* Discard vendor prefix */
+               strsep(&compatible, ",");
+
+               fdtfile = calloc(1, strlen(vendor) + strlen(compatible) +
+                                strlen(suffix) + 1);
+               if (!fdtfile)
+                       return -ENOMEM;
+
+               sprintf(fdtfile, "%s%s%s", vendor, compatible, suffix);
+
+               env_set("fdtfile", fdtfile);
+               free(fdtfile);
+       }
+
+       return 0;
+}
+
 int board_late_init(void)
 {
        u32 reg = 0;
@@ -503,12 +564,21 @@ int board_late_init(void)
        char *new_targets;
        char *env_targets;
        int ret;
+       ulong initrd_hi;
+
+#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;
        }
 
+       ret = set_fdtfile();
+       if (ret)
+               return ret;
+
        ret = zynqmp_mmio_read((ulong)&crlapb_base->boot_mode, &reg);
        if (ret)
                return -EINVAL;
@@ -527,7 +597,7 @@ int board_late_init(void)
                break;
        case JTAG_MODE:
                puts("JTAG_MODE\n");
-               mode = "pxe dhcp";
+               mode = "jtag pxe dhcp";
                env_set("modeboot", "jtagboot");
                break;
        case QSPI_MODE_24BIT:
@@ -538,12 +608,23 @@ int board_late_init(void)
                break;
        case EMMC_MODE:
                puts("EMMC_MODE\n");
-               mode = "mmc0";
-               env_set("modeboot", "emmcboot");
+               if (uclass_get_device_by_name(UCLASS_MMC,
+                                             "mmc@ff160000", &dev) &&
+                   uclass_get_device_by_name(UCLASS_MMC,
+                                             "sdhci@ff160000", &dev)) {
+                       puts("Boot from EMMC but without SD0 enabled!\n");
+                       return -1;
+               }
+               debug("mmc0 device found at %p, seq %d\n", dev, dev->seq);
+
+               mode = "mmc";
+               bootseq = dev->seq;
                break;
        case SD_MODE:
                puts("SD_MODE\n");
                if (uclass_get_device_by_name(UCLASS_MMC,
+                                             "mmc@ff160000", &dev) &&
+                   uclass_get_device_by_name(UCLASS_MMC,
                                              "sdhci@ff160000", &dev)) {
                        puts("Boot from SD0 but without SD0 enabled!\n");
                        return -1;
@@ -560,6 +641,8 @@ int board_late_init(void)
        case SD_MODE1:
                puts("SD_MODE1\n");
                if (uclass_get_device_by_name(UCLASS_MMC,
+                                             "mmc@ff170000", &dev) &&
+                   uclass_get_device_by_name(UCLASS_MMC,
                                              "sdhci@ff170000", &dev)) {
                        puts("Boot from SD1 but without SD1 enabled!\n");
                        return -1;
@@ -596,6 +679,8 @@ int board_late_init(void)
 
        new_targets = calloc(1, strlen(mode) + env_targets_len + 2 +
                             bootseq_len);
+       if (!new_targets)
+               return -ENOMEM;
 
        if (bootseq >= 0)
                sprintf(new_targets, "%s%x %s", mode, bootseq,
@@ -606,10 +691,17 @@ int board_late_init(void)
 
        env_set("boot_targets", new_targets);
 
+       initrd_hi = gd->start_addr_sp - CONFIG_STACK_SIZE;
+       initrd_hi = round_down(initrd_hi, SZ_16M);
+       env_set_addr("initrd_high", (void *)initrd_hi);
+
+       env_set_hex("script_offset_f", CONFIG_BOOT_SCRIPT_OFFSET);
+
        reset_reason();
 
        return 0;
 }
+#endif
 
 int checkboard(void)
 {