Merge tag 'u-boot-imx-20200825' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
[platform/kernel/u-boot.git] / board / xilinx / zynqmp / zynqmp.c
index 0c331e3..b4e7301 100644 (file)
@@ -5,7 +5,13 @@
  */
 
 #include <common.h>
+#include <command.h>
+#include <cpu_func.h>
+#include <debug_uart.h>
 #include <env.h>
+#include <init.h>
+#include <log.h>
+#include <net.h>
 #include <sata.h>
 #include <ahci.h>
 #include <scsi.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/arch/psu_init_gpl.h>
+#include <asm/cache.h>
 #include <asm/io.h>
+#include <asm/ptrace.h>
 #include <dm/device.h>
 #include <dm/uclass.h>
 #include <usb.h>
 #include <dwc3-uboot.h>
 #include <zynqmppl.h>
+#include <zynqmp_firmware.h>
 #include <g_dnl.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
 #include <linux/sizes.h>
+#include "../common/board.h"
 
 #include "pm_cfg_obj.h"
 
@@ -174,70 +186,17 @@ static const struct {
                .id = 0x66,
                .name = "39dr",
        },
+       {
+               .id = 0x7b,
+               .name = "48dr",
+       },
+       {
+               .id = 0x7e,
+               .name = "49dr",
+       },
 };
 #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(&regs);
-
-               /*
-                * 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_IPDIS_VCU_BIT           8
@@ -254,9 +213,28 @@ static char *zynqmp_get_silicon_idcode_name(void)
        u32 i, id, ver, j;
        char *buf;
        static char name[ZYNQMP_VERSION_SIZE];
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+
+       xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
+
+       /*
+        * Firmware returns:
+        * payload[0][31:0]  = status of the operation
+        * payload[1]] = IDCODE
+        * payload[2][19:0]  = Version
+        * payload[2][28:20] = EXTENDED_IDCODE
+        * payload[2][29] = PL_INIT
+        */
+
+       /* Get IDCODE field */
+       id = ret_payload[1];
+       id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK;
+       id >>=  ZYNQMP_CSU_IDCODE_SVD_SHIFT;
+
+       /* Shift silicon version info */
+       ver = ret_payload[2] >> ZYNQMP_CSU_VERSION_EMPTY_SHIFT;
 
-       id = chip_id(IDCODE);
-       ver = chip_id(IDCODE2);
+       debug("%s, ID: 0x%0X, Ver: 0x%0X\r\n", __func__, id, ver);
 
        for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
                if (zynqmp_devices[i].id == id) {
@@ -308,29 +286,50 @@ 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)
-       u32 pm_api_version;
+#if defined(CONFIG_ZYNQMP_PSU_INIT_ENABLED)
+       int ret;
 
-       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);
+       ret = psu_init();
+       if (ret)
+               return ret;
 
-       if (pm_api_version < ZYNQMP_PM_VERSION)
-               panic("PMUFW version error. Expected: v%d.%d\n",
-                     ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR);
+       /* Delay is required for clocks to be propagated */
+       udelay(1000000);
 #endif
 
-#if defined(CONFIG_ZYNQMP_PSU_INIT_ENABLED)
-       ret = psu_init();
+#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%d\n", multiboot);
+
+       return 0;
 }
 
+#define PS_SYSMON_ANALOG_BUS_VAL       0x3210
+#define PS_SYSMON_ANALOG_BUS_REG       0xFFA50914
+
 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)
@@ -340,17 +339,21 @@ int board_init(void)
 
        printf("EL Level:\tEL%d\n", current_el());
 
+       /* Bug in ROM sets wrong value in this register */
+       writel(PS_SYSMON_ANALOG_BUS_VAL, PS_SYSMON_ANALOG_BUS_REG);
+
 #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);
-       }
+       zynqmppl.name = zynqmp_get_silicon_idcode_name();
+       printf("Chip ID:\t%s\n", zynqmppl.name);
+       fpga_init();
+       fpga_add(fpga_xilinx, &zynqmppl);
 #endif
 
+       if (current_el() == 3)
+               multi_boot();
+
        return 0;
 }
 
@@ -380,7 +383,7 @@ int board_early_init_r(void)
 }
 
 unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
-                        char * const argv[])
+                        char *const argv[])
 {
        int ret = 0;
 
@@ -482,7 +485,7 @@ static int reset_reason(void)
 
        env_set("reset_reason", reason);
 
-       ret = zynqmp_mmio_write(~0, ~0, (ulong)&crlapb_base->reset_reason);
+       ret = zynqmp_mmio_write((ulong)&crlapb_base->reset_reason, ~0, ~0);
        if (ret)
                return -EINVAL;
 
@@ -494,23 +497,30 @@ static int set_fdtfile(void)
        char *compatible, *fdtfile;
        const char *suffix = ".dtb";
        const char *vendor = "xilinx/";
+       int fdt_compat_len;
 
        if (env_get("fdtfile"))
                return 0;
 
-       compatible = (char *)fdt_getprop(gd->fdt_blob, 0, "compatible", NULL);
-       if (compatible) {
+       compatible = (char *)fdt_getprop(gd->fdt_blob, 0, "compatible",
+                                        &fdt_compat_len);
+       if (compatible && fdt_compat_len) {
+               char *name;
+
                debug("Compatible: %s\n", compatible);
 
-               /* Discard vendor prefix */
-               strsep(&compatible, ",");
+               name = strchr(compatible, ',');
+               if (!name)
+                       return -EINVAL;
+
+               name++;
 
-               fdtfile = calloc(1, strlen(vendor) + strlen(compatible) +
+               fdtfile = calloc(1, strlen(vendor) + strlen(name) +
                                 strlen(suffix) + 1);
                if (!fdtfile)
                        return -ENOMEM;
 
-               sprintf(fdtfile, "%s%s%s", vendor, compatible, suffix);
+               sprintf(fdtfile, "%s%s%s", vendor, name, suffix);
 
                env_set("fdtfile", fdtfile);
                free(fdtfile);
@@ -519,9 +529,26 @@ static int set_fdtfile(void)
        return 0;
 }
 
-int board_late_init(void)
+static u8 zynqmp_get_bootmode(void)
 {
+       u8 bootmode;
        u32 reg = 0;
+       int ret;
+
+       ret = zynqmp_mmio_read((ulong)&crlapb_base->boot_mode, &reg);
+       if (ret)
+               return -EINVAL;
+
+       if (reg >> BOOT_MODE_ALT_SHIFT)
+               reg >>= BOOT_MODE_ALT_SHIFT;
+
+       bootmode = reg & BOOT_MODES_MASK;
+
+       return bootmode;
+}
+
+int board_late_init(void)
+{
        u8 bootmode;
        struct udevice *dev;
        int bootseq = -1;
@@ -531,7 +558,6 @@ 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();
@@ -542,18 +568,14 @@ int board_late_init(void)
                return 0;
        }
 
+       if (!CONFIG_IS_ENABLED(ENV_VARS_UBOOT_RUNTIME_CONFIG))
+               return 0;
+
        ret = set_fdtfile();
        if (ret)
                return ret;
 
-       ret = zynqmp_mmio_read((ulong)&crlapb_base->boot_mode, &reg);
-       if (ret)
-               return -EINVAL;
-
-       if (reg >> BOOT_MODE_ALT_SHIFT)
-               reg >>= BOOT_MODE_ALT_SHIFT;
-
-       bootmode = reg & BOOT_MODES_MASK;
+       bootmode = zynqmp_get_bootmode();
 
        puts("Bootmode: ");
        switch (bootmode) {
@@ -564,7 +586,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:
@@ -575,8 +597,17 @@ 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");
@@ -649,13 +680,9 @@ 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);
-
        reset_reason();
 
-       return 0;
+       return board_late_init_xilinx();
 }
 #endif