uboot/board/xilinx/zynqmp/zynqmp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2014 - 2015 Xilinx, Inc.
   4 * Michal Simek <michal.simek@xilinx.com>
   5 */
   6
   7#include <common.h>
   8#include <sata.h>
   9#include <ahci.h>
  10#include <scsi.h>
  11#include <malloc.h>
  12#include <wdt.h>
  13#include <asm/arch/clk.h>
  14#include <asm/arch/hardware.h>
  15#include <asm/arch/sys_proto.h>
  16#include <asm/arch/psu_init_gpl.h>
  17#include <asm/io.h>
  18#include <dm/device.h>
  19#include <dm/uclass.h>
  20#include <usb.h>
  21#include <dwc3-uboot.h>
  22#include <zynqmppl.h>
  23#include <g_dnl.h>
  24
  25DECLARE_GLOBAL_DATA_PTR;
  26
  27#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
  28    !defined(CONFIG_SPL_BUILD)
  29static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC;
  30
  31static const struct {
  32        u32 id;
  33        u32 ver;
  34        char *name;
  35        bool evexists;
  36} zynqmp_devices[] = {
  37        {
  38                .id = 0x10,
  39                .name = "3eg",
  40        },
  41        {
  42                .id = 0x10,
  43                .ver = 0x2c,
  44                .name = "3cg",
  45        },
  46        {
  47                .id = 0x11,
  48                .name = "2eg",
  49        },
  50        {
  51                .id = 0x11,
  52                .ver = 0x2c,
  53                .name = "2cg",
  54        },
  55        {
  56                .id = 0x20,
  57                .name = "5ev",
  58                .evexists = 1,
  59        },
  60        {
  61                .id = 0x20,
  62                .ver = 0x100,
  63                .name = "5eg",
  64                .evexists = 1,
  65        },
  66        {
  67                .id = 0x20,
  68                .ver = 0x12c,
  69                .name = "5cg",
  70                .evexists = 1,
  71        },
  72        {
  73                .id = 0x21,
  74                .name = "4ev",
  75                .evexists = 1,
  76        },
  77        {
  78                .id = 0x21,
  79                .ver = 0x100,
  80                .name = "4eg",
  81                .evexists = 1,
  82        },
  83        {
  84                .id = 0x21,
  85                .ver = 0x12c,
  86                .name = "4cg",
  87                .evexists = 1,
  88        },
  89        {
  90                .id = 0x30,
  91                .name = "7ev",
  92                .evexists = 1,
  93        },
  94        {
  95                .id = 0x30,
  96                .ver = 0x100,
  97                .name = "7eg",
  98                .evexists = 1,
  99        },
 100        {
 101                .id = 0x30,
 102                .ver = 0x12c,
 103                .name = "7cg",
 104                .evexists = 1,
 105        },
 106        {
 107                .id = 0x38,
 108                .name = "9eg",
 109        },
 110        {
 111                .id = 0x38,
 112                .ver = 0x2c,
 113                .name = "9cg",
 114        },
 115        {
 116                .id = 0x39,
 117                .name = "6eg",
 118        },
 119        {
 120                .id = 0x39,
 121                .ver = 0x2c,
 122                .name = "6cg",
 123        },
 124        {
 125                .id = 0x40,
 126                .name = "11eg",
 127        },
 128        { /* For testing purpose only */
 129                .id = 0x50,
 130                .ver = 0x2c,
 131                .name = "15cg",
 132        },
 133        {
 134                .id = 0x50,
 135                .name = "15eg",
 136        },
 137        {
 138                .id = 0x58,
 139                .name = "19eg",
 140        },
 141        {
 142                .id = 0x59,
 143                .name = "17eg",
 144        },
 145        {
 146                .id = 0x61,
 147                .name = "21dr",
 148        },
 149        {
 150                .id = 0x63,
 151                .name = "23dr",
 152        },
 153        {
 154                .id = 0x65,
 155                .name = "25dr",
 156        },
 157        {
 158                .id = 0x64,
 159                .name = "27dr",
 160        },
 161        {
 162                .id = 0x60,
 163                .name = "28dr",
 164        },
 165        {
 166                .id = 0x62,
 167                .name = "29dr",
 168        },
 169        {
 170                .id = 0x66,
 171                .name = "39dr",
 172        },
 173};
 174#endif
 175
 176int chip_id(unsigned char id)
 177{
 178        struct pt_regs regs;
 179        int val = -EINVAL;
 180
 181        if (current_el() != 3) {
 182                regs.regs[0] = ZYNQMP_SIP_SVC_CSU_DMA_CHIPID;
 183                regs.regs[1] = 0;
 184                regs.regs[2] = 0;
 185                regs.regs[3] = 0;
 186
 187                smc_call(&regs);
 188
 189                /*
 190                 * SMC returns:
 191                 * regs[0][31:0]  = status of the operation
 192                 * regs[0][63:32] = CSU.IDCODE register
 193                 * regs[1][31:0]  = CSU.version register
 194                 * regs[1][63:32] = CSU.IDCODE2 register
 195                 */
 196                switch (id) {
 197                case IDCODE:
 198                        regs.regs[0] = upper_32_bits(regs.regs[0]);
 199                        regs.regs[0] &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
 200                                        ZYNQMP_CSU_IDCODE_SVD_MASK;
 201                        regs.regs[0] >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
 202                        val = regs.regs[0];
 203                        break;
 204                case VERSION:
 205                        regs.regs[1] = lower_32_bits(regs.regs[1]);
 206                        regs.regs[1] &= ZYNQMP_CSU_SILICON_VER_MASK;
 207                        val = regs.regs[1];
 208                        break;
 209                case IDCODE2:
 210                        regs.regs[1] = lower_32_bits(regs.regs[1]);
 211                        regs.regs[1] >>= ZYNQMP_CSU_VERSION_EMPTY_SHIFT;
 212                        val = regs.regs[1];
 213                        break;
 214                default:
 215                        printf("%s, Invalid Req:0x%x\n", __func__, id);
 216                }
 217        } else {
 218                switch (id) {
 219                case IDCODE:
 220                        val = readl(ZYNQMP_CSU_IDCODE_ADDR);
 221                        val &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
 222                               ZYNQMP_CSU_IDCODE_SVD_MASK;
 223                        val >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
 224                        break;
 225                case VERSION:
 226                        val = readl(ZYNQMP_CSU_VER_ADDR);
 227                        val &= ZYNQMP_CSU_SILICON_VER_MASK;
 228                        break;
 229                default:
 230                        printf("%s, Invalid Req:0x%x\n", __func__, id);
 231                }
 232        }
 233
 234        return val;
 235}
 236
 237#define ZYNQMP_VERSION_SIZE             9
 238#define ZYNQMP_PL_STATUS_BIT            9
 239#define ZYNQMP_IPDIS_VCU_BIT            8
 240#define ZYNQMP_PL_STATUS_MASK           BIT(ZYNQMP_PL_STATUS_BIT)
 241#define ZYNQMP_CSU_VERSION_MASK         ~(ZYNQMP_PL_STATUS_MASK)
 242#define ZYNQMP_CSU_VCUDIS_VER_MASK      ZYNQMP_CSU_VERSION_MASK & \
 243                                        ~BIT(ZYNQMP_IPDIS_VCU_BIT)
 244#define MAX_VARIANTS_EV                 3
 245
 246#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
 247        !defined(CONFIG_SPL_BUILD)
 248static char *zynqmp_get_silicon_idcode_name(void)
 249{
 250        u32 i, id, ver, j;
 251        char *buf;
 252        static char name[ZYNQMP_VERSION_SIZE];
 253
 254        id = chip_id(IDCODE);
 255        ver = chip_id(IDCODE2);
 256
 257        for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
 258                if (zynqmp_devices[i].id == id) {
 259                        if (zynqmp_devices[i].evexists &&
 260                            !(ver & ZYNQMP_PL_STATUS_MASK))
 261                                break;
 262                        if (zynqmp_devices[i].ver == (ver &
 263                            ZYNQMP_CSU_VERSION_MASK))
 264                                break;
 265                }
 266        }
 267
 268        if (i >= ARRAY_SIZE(zynqmp_devices))
 269                return "unknown";
 270
 271        strncat(name, "zu", 2);
 272        if (!zynqmp_devices[i].evexists ||
 273            (ver & ZYNQMP_PL_STATUS_MASK)) {
 274                strncat(name, zynqmp_devices[i].name,
 275                        ZYNQMP_VERSION_SIZE - 3);
 276                return name;
 277        }
 278
 279        /*
 280         * Here we are means, PL not powered up and ev variant
 281         * exists. So, we need to ignore VCU disable bit(8) in
 282         * version and findout if its CG or EG/EV variant.
 283         */
 284        for (j = 0; j < MAX_VARIANTS_EV; j++, i++) {
 285                if ((zynqmp_devices[i].ver & ~BIT(ZYNQMP_IPDIS_VCU_BIT)) ==
 286                    (ver & ZYNQMP_CSU_VCUDIS_VER_MASK)) {
 287                        strncat(name, zynqmp_devices[i].name,
 288                                ZYNQMP_VERSION_SIZE - 3);
 289                        break;
 290                }
 291        }
 292
 293        if (j >= MAX_VARIANTS_EV)
 294                return "unknown";
 295
 296        if (strstr(name, "eg") || strstr(name, "ev")) {
 297                buf = strstr(name, "e");
 298                *buf = '\0';
 299        }
 300
 301        return name;
 302}
 303#endif
 304
 305int board_early_init_f(void)
 306{
 307        int ret = 0;
 308#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_CLK_ZYNQMP)
 309        u32 pm_api_version;
 310
 311        pm_api_version = zynqmp_pmufw_version();
 312        printf("PMUFW:\tv%d.%d\n",
 313               pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT,
 314               pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK);
 315
 316        if (pm_api_version < ZYNQMP_PM_VERSION)
 317                panic("PMUFW version error. Expected: v%d.%d\n",
 318                      ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR);
 319#endif
 320
 321#if defined(CONFIG_ZYNQMP_PSU_INIT_ENABLED)
 322        ret = psu_init();
 323#endif
 324
 325        return ret;
 326}
 327
 328int board_init(void)
 329{
 330        printf("EL Level:\tEL%d\n", current_el());
 331
 332#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
 333    !defined(CONFIG_SPL_BUILD) || (defined(CONFIG_SPL_FPGA_SUPPORT) && \
 334    defined(CONFIG_SPL_BUILD))
 335        if (current_el() != 3) {
 336                zynqmppl.name = zynqmp_get_silicon_idcode_name();
 337                printf("Chip ID:\t%s\n", zynqmppl.name);
 338                fpga_init();
 339                fpga_add(fpga_xilinx, &zynqmppl);
 340        }
 341#endif
 342
 343        return 0;
 344}
 345
 346int board_early_init_r(void)
 347{
 348        u32 val;
 349
 350        if (current_el() != 3)
 351                return 0;
 352
 353        val = readl(&crlapb_base->timestamp_ref_ctrl);
 354        val &= ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT;
 355
 356        if (!val) {
 357                val = readl(&crlapb_base->timestamp_ref_ctrl);
 358                val |= ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT;
 359                writel(val, &crlapb_base->timestamp_ref_ctrl);
 360
 361                /* Program freq register in System counter */
 362                writel(zynqmp_get_system_timer_freq(),
 363                       &iou_scntr_secure->base_frequency_id_register);
 364                /* And enable system counter */
 365                writel(ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_EN,
 366                       &iou_scntr_secure->counter_control_register);
 367        }
 368        return 0;
 369}
 370
 371unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
 372                         char * const argv[])
 373{
 374        int ret = 0;
 375
 376        if (current_el() > 1) {
 377                smp_kick_all_cpus();
 378                dcache_disable();
 379                armv8_switch_to_el1(0x0, 0, 0, 0, (unsigned long)entry,
 380                                    ES_TO_AARCH64);
 381        } else {
 382                printf("FAIL: current EL is not above EL1\n");
 383                ret = EINVAL;
 384        }
 385        return ret;
 386}
 387
 388#if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE)
 389int dram_init_banksize(void)
 390{
 391        int ret;
 392
 393        ret = fdtdec_setup_memory_banksize();
 394        if (ret)
 395                return ret;
 396
 397        mem_map_fill();
 398
 399        return 0;
 400}
 401
 402int dram_init(void)
 403{
 404        if (fdtdec_setup_mem_size_base() != 0)
 405                return -EINVAL;
 406
 407        return 0;
 408}
 409#else
 410int dram_init_banksize(void)
 411{
 412#if defined(CONFIG_NR_DRAM_BANKS)
 413        gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
 414        gd->bd->bi_dram[0].size = get_effective_memsize();
 415#endif
 416
 417        mem_map_fill();
 418
 419        return 0;
 420}
 421
 422int dram_init(void)
 423{
 424        gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
 425                                    CONFIG_SYS_SDRAM_SIZE);
 426
 427        return 0;
 428}
 429#endif
 430
 431void reset_cpu(ulong addr)
 432{
 433}
 434
 435#if defined(CONFIG_BOARD_LATE_INIT)
 436static const struct {
 437        u32 bit;
 438        const char *name;
 439} reset_reasons[] = {
 440        { RESET_REASON_DEBUG_SYS, "DEBUG" },
 441        { RESET_REASON_SOFT, "SOFT" },
 442        { RESET_REASON_SRST, "SRST" },
 443        { RESET_REASON_PSONLY, "PS-ONLY" },
 444        { RESET_REASON_PMU, "PMU" },
 445        { RESET_REASON_INTERNAL, "INTERNAL" },
 446        { RESET_REASON_EXTERNAL, "EXTERNAL" },
 447        {}
 448};
 449
 450static int reset_reason(void)
 451{
 452        u32 reg;
 453        int i, ret;
 454        const char *reason = NULL;
 455
 456        ret = zynqmp_mmio_read((ulong)&crlapb_base->reset_reason, &reg);
 457        if (ret)
 458                return -EINVAL;
 459
 460        puts("Reset reason:\t");
 461
 462        for (i = 0; i < ARRAY_SIZE(reset_reasons); i++) {
 463                if (reg & reset_reasons[i].bit) {
 464                        reason = reset_reasons[i].name;
 465                        printf("%s ", reset_reasons[i].name);
 466                        break;
 467                }
 468        }
 469
 470        puts("\n");
 471
 472        env_set("reset_reason", reason);
 473
 474        ret = zynqmp_mmio_write(~0, ~0, (ulong)&crlapb_base->reset_reason);
 475        if (ret)
 476                return -EINVAL;
 477
 478        return ret;
 479}
 480
 481static int set_fdtfile(void)
 482{
 483        char *compatible, *fdtfile;
 484        const char *suffix = ".dtb";
 485        const char *vendor = "xilinx/";
 486
 487        if (env_get("fdtfile"))
 488                return 0;
 489
 490        compatible = (char *)fdt_getprop(gd->fdt_blob, 0, "compatible", NULL);
 491        if (compatible) {
 492                debug("Compatible: %s\n", compatible);
 493
 494                /* Discard vendor prefix */
 495                strsep(&compatible, ",");
 496
 497                fdtfile = calloc(1, strlen(vendor) + strlen(compatible) +
 498                                 strlen(suffix) + 1);
 499                if (!fdtfile)
 500                        return -ENOMEM;
 501
 502                sprintf(fdtfile, "%s%s%s", vendor, compatible, suffix);
 503
 504                env_set("fdtfile", fdtfile);
 505                free(fdtfile);
 506        }
 507
 508        return 0;
 509}
 510
 511int board_late_init(void)
 512{
 513        u32 reg = 0;
 514        u8 bootmode;
 515        struct udevice *dev;
 516        int bootseq = -1;
 517        int bootseq_len = 0;
 518        int env_targets_len = 0;
 519        const char *mode;
 520        char *new_targets;
 521        char *env_targets;
 522        int ret;
 523
 524#if defined(CONFIG_USB_ETHER) && !defined(CONFIG_USB_GADGET_DOWNLOAD)
 525        usb_ether_init();
 526#endif
 527
 528        if (!(gd->flags & GD_FLG_ENV_DEFAULT)) {
 529                debug("Saved variables - Skipping\n");
 530                return 0;
 531        }
 532
 533        ret = set_fdtfile();
 534        if (ret)
 535                return ret;
 536
 537        ret = zynqmp_mmio_read((ulong)&crlapb_base->boot_mode, &reg);
 538        if (ret)
 539                return -EINVAL;
 540
 541        if (reg >> BOOT_MODE_ALT_SHIFT)
 542                reg >>= BOOT_MODE_ALT_SHIFT;
 543
 544        bootmode = reg & BOOT_MODES_MASK;
 545
 546        puts("Bootmode: ");
 547        switch (bootmode) {
 548        case USB_MODE:
 549                puts("USB_MODE\n");
 550                mode = "usb";
 551                env_set("modeboot", "usb_dfu_spl");
 552                break;
 553        case JTAG_MODE:
 554                puts("JTAG_MODE\n");
 555                mode = "pxe dhcp";
 556                env_set("modeboot", "jtagboot");
 557                break;
 558        case QSPI_MODE_24BIT:
 559        case QSPI_MODE_32BIT:
 560                mode = "qspi0";
 561                puts("QSPI_MODE\n");
 562                env_set("modeboot", "qspiboot");
 563                break;
 564        case EMMC_MODE:
 565                puts("EMMC_MODE\n");
 566                mode = "mmc0";
 567                env_set("modeboot", "emmcboot");
 568                break;
 569        case SD_MODE:
 570                puts("SD_MODE\n");
 571                if (uclass_get_device_by_name(UCLASS_MMC,
 572                                              "mmc@ff160000", &dev) &&
 573                    uclass_get_device_by_name(UCLASS_MMC,
 574                                              "sdhci@ff160000", &dev)) {
 575                        puts("Boot from SD0 but without SD0 enabled!\n");
 576                        return -1;
 577                }
 578                debug("mmc0 device found at %p, seq %d\n", dev, dev->seq);
 579
 580                mode = "mmc";
 581                bootseq = dev->seq;
 582                env_set("modeboot", "sdboot");
 583                break;
 584        case SD1_LSHFT_MODE:
 585                puts("LVL_SHFT_");
 586                /* fall through */
 587        case SD_MODE1:
 588                puts("SD_MODE1\n");
 589                if (uclass_get_device_by_name(UCLASS_MMC,
 590                                              "mmc@ff170000", &dev) &&
 591                    uclass_get_device_by_name(UCLASS_MMC,
 592                                              "sdhci@ff170000", &dev)) {
 593                        puts("Boot from SD1 but without SD1 enabled!\n");
 594                        return -1;
 595                }
 596                debug("mmc1 device found at %p, seq %d\n", dev, dev->seq);
 597
 598                mode = "mmc";
 599                bootseq = dev->seq;
 600                env_set("modeboot", "sdboot");
 601                break;
 602        case NAND_MODE:
 603                puts("NAND_MODE\n");
 604                mode = "nand0";
 605                env_set("modeboot", "nandboot");
 606                break;
 607        default:
 608                mode = "";
 609                printf("Invalid Boot Mode:0x%x\n", bootmode);
 610                break;
 611        }
 612
 613        if (bootseq >= 0) {
 614                bootseq_len = snprintf(NULL, 0, "%i", bootseq);
 615                debug("Bootseq len: %x\n", bootseq_len);
 616        }
 617
 618        /*
 619         * One terminating char + one byte for space between mode
 620         * and default boot_targets
 621         */
 622        env_targets = env_get("boot_targets");
 623        if (env_targets)
 624                env_targets_len = strlen(env_targets);
 625
 626        new_targets = calloc(1, strlen(mode) + env_targets_len + 2 +
 627                             bootseq_len);
 628        if (!new_targets)
 629                return -ENOMEM;
 630
 631        if (bootseq >= 0)
 632                sprintf(new_targets, "%s%x %s", mode, bootseq,
 633                        env_targets ? env_targets : "");
 634        else
 635                sprintf(new_targets, "%s %s", mode,
 636                        env_targets ? env_targets : "");
 637
 638        env_set("boot_targets", new_targets);
 639
 640        reset_reason();
 641
 642        return 0;
 643}
 644#endif
 645
 646int checkboard(void)
 647{
 648        puts("Board: Xilinx ZynqMP\n");
 649        return 0;
 650}
 651