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