1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. 4*91f16700Schasinglulu * 5*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 6*91f16700Schasinglulu */ 7*91f16700Schasinglulu 8*91f16700Schasinglulu #include <stdbool.h> 9*91f16700Schasinglulu #include <string.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <common/debug.h> 12*91f16700Schasinglulu #include <drivers/generic_delay_timer.h> 13*91f16700Schasinglulu #include <lib/mmio.h> 14*91f16700Schasinglulu #include <lib/smccc.h> 15*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables.h> 16*91f16700Schasinglulu #include <plat/common/platform.h> 17*91f16700Schasinglulu #include <services/arm_arch_svc.h> 18*91f16700Schasinglulu 19*91f16700Schasinglulu #include <plat_ipi.h> 20*91f16700Schasinglulu #include <plat_private.h> 21*91f16700Schasinglulu #include <plat_startup.h> 22*91f16700Schasinglulu 23*91f16700Schasinglulu #include "zynqmp_pm_api_sys.h" 24*91f16700Schasinglulu 25*91f16700Schasinglulu /* 26*91f16700Schasinglulu * Table of regions to map using the MMU. 27*91f16700Schasinglulu * This doesn't include TZRAM as the 'mem_layout' argument passed to 28*91f16700Schasinglulu * configure_mmu_elx() will give the available subset of that, 29*91f16700Schasinglulu */ 30*91f16700Schasinglulu const mmap_region_t plat_zynqmp_mmap[] = { 31*91f16700Schasinglulu { DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, 32*91f16700Schasinglulu { DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, 33*91f16700Schasinglulu { CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, 34*91f16700Schasinglulu {0} 35*91f16700Schasinglulu }; 36*91f16700Schasinglulu 37*91f16700Schasinglulu const mmap_region_t *plat_get_mmap(void) 38*91f16700Schasinglulu { 39*91f16700Schasinglulu return plat_zynqmp_mmap; 40*91f16700Schasinglulu } 41*91f16700Schasinglulu 42*91f16700Schasinglulu static uint32_t zynqmp_get_silicon_ver(void) 43*91f16700Schasinglulu { 44*91f16700Schasinglulu static unsigned int ver; 45*91f16700Schasinglulu 46*91f16700Schasinglulu if (!ver) { 47*91f16700Schasinglulu ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + 48*91f16700Schasinglulu ZYNQMP_CSU_VERSION_OFFSET); 49*91f16700Schasinglulu ver &= ZYNQMP_SILICON_VER_MASK; 50*91f16700Schasinglulu ver >>= ZYNQMP_SILICON_VER_SHIFT; 51*91f16700Schasinglulu } 52*91f16700Schasinglulu 53*91f16700Schasinglulu return ver; 54*91f16700Schasinglulu } 55*91f16700Schasinglulu 56*91f16700Schasinglulu uint32_t get_uart_clk(void) 57*91f16700Schasinglulu { 58*91f16700Schasinglulu unsigned int ver = zynqmp_get_silicon_ver(); 59*91f16700Schasinglulu 60*91f16700Schasinglulu if (ver == ZYNQMP_CSU_VERSION_QEMU) { 61*91f16700Schasinglulu return 133000000; 62*91f16700Schasinglulu } else { 63*91f16700Schasinglulu return 100000000; 64*91f16700Schasinglulu } 65*91f16700Schasinglulu } 66*91f16700Schasinglulu 67*91f16700Schasinglulu #if LOG_LEVEL >= LOG_LEVEL_NOTICE 68*91f16700Schasinglulu static const struct { 69*91f16700Schasinglulu uint8_t id; 70*91f16700Schasinglulu bool evexists; 71*91f16700Schasinglulu uint16_t ver; 72*91f16700Schasinglulu char *name; 73*91f16700Schasinglulu } __packed zynqmp_devices[] = { 74*91f16700Schasinglulu { 75*91f16700Schasinglulu .id = 0x10, 76*91f16700Schasinglulu .name = "XCZU3EG", 77*91f16700Schasinglulu }, 78*91f16700Schasinglulu { 79*91f16700Schasinglulu .id = 0x10, 80*91f16700Schasinglulu .ver = 0x2c, 81*91f16700Schasinglulu .name = "XCZU3CG", 82*91f16700Schasinglulu }, 83*91f16700Schasinglulu { 84*91f16700Schasinglulu .id = 0x11, 85*91f16700Schasinglulu .name = "XCZU2EG", 86*91f16700Schasinglulu }, 87*91f16700Schasinglulu { 88*91f16700Schasinglulu .id = 0x11, 89*91f16700Schasinglulu .ver = 0x2c, 90*91f16700Schasinglulu .name = "XCZU2CG", 91*91f16700Schasinglulu }, 92*91f16700Schasinglulu { 93*91f16700Schasinglulu .id = 0x20, 94*91f16700Schasinglulu .name = "XCZU5EV", 95*91f16700Schasinglulu .evexists = true, 96*91f16700Schasinglulu }, 97*91f16700Schasinglulu { 98*91f16700Schasinglulu .id = 0x20, 99*91f16700Schasinglulu .ver = 0x100, 100*91f16700Schasinglulu .name = "XCZU5EG", 101*91f16700Schasinglulu .evexists = true, 102*91f16700Schasinglulu }, 103*91f16700Schasinglulu { 104*91f16700Schasinglulu .id = 0x20, 105*91f16700Schasinglulu .ver = 0x12c, 106*91f16700Schasinglulu .name = "XCZU5CG", 107*91f16700Schasinglulu }, 108*91f16700Schasinglulu { 109*91f16700Schasinglulu .id = 0x21, 110*91f16700Schasinglulu .name = "XCZU4EV", 111*91f16700Schasinglulu .evexists = true, 112*91f16700Schasinglulu }, 113*91f16700Schasinglulu { 114*91f16700Schasinglulu .id = 0x21, 115*91f16700Schasinglulu .ver = 0x100, 116*91f16700Schasinglulu .name = "XCZU4EG", 117*91f16700Schasinglulu .evexists = true, 118*91f16700Schasinglulu }, 119*91f16700Schasinglulu { 120*91f16700Schasinglulu .id = 0x21, 121*91f16700Schasinglulu .ver = 0x12c, 122*91f16700Schasinglulu .name = "XCZU4CG", 123*91f16700Schasinglulu }, 124*91f16700Schasinglulu { 125*91f16700Schasinglulu .id = 0x30, 126*91f16700Schasinglulu .name = "XCZU7EV", 127*91f16700Schasinglulu .evexists = true, 128*91f16700Schasinglulu }, 129*91f16700Schasinglulu { 130*91f16700Schasinglulu .id = 0x30, 131*91f16700Schasinglulu .ver = 0x100, 132*91f16700Schasinglulu .name = "XCZU7EG", 133*91f16700Schasinglulu .evexists = true, 134*91f16700Schasinglulu }, 135*91f16700Schasinglulu { 136*91f16700Schasinglulu .id = 0x30, 137*91f16700Schasinglulu .ver = 0x12c, 138*91f16700Schasinglulu .name = "XCZU7CG", 139*91f16700Schasinglulu }, 140*91f16700Schasinglulu { 141*91f16700Schasinglulu .id = 0x38, 142*91f16700Schasinglulu .name = "XCZU9EG", 143*91f16700Schasinglulu }, 144*91f16700Schasinglulu { 145*91f16700Schasinglulu .id = 0x38, 146*91f16700Schasinglulu .ver = 0x2c, 147*91f16700Schasinglulu .name = "XCZU9CG", 148*91f16700Schasinglulu }, 149*91f16700Schasinglulu { 150*91f16700Schasinglulu .id = 0x39, 151*91f16700Schasinglulu .name = "XCZU6EG", 152*91f16700Schasinglulu }, 153*91f16700Schasinglulu { 154*91f16700Schasinglulu .id = 0x39, 155*91f16700Schasinglulu .ver = 0x2c, 156*91f16700Schasinglulu .name = "XCZU6CG", 157*91f16700Schasinglulu }, 158*91f16700Schasinglulu { 159*91f16700Schasinglulu .id = 0x40, 160*91f16700Schasinglulu .name = "XCZU11EG", 161*91f16700Schasinglulu }, 162*91f16700Schasinglulu { 163*91f16700Schasinglulu .id = 0x50, 164*91f16700Schasinglulu .name = "XCZU15EG", 165*91f16700Schasinglulu }, 166*91f16700Schasinglulu { 167*91f16700Schasinglulu .id = 0x58, 168*91f16700Schasinglulu .name = "XCZU19EG", 169*91f16700Schasinglulu }, 170*91f16700Schasinglulu { 171*91f16700Schasinglulu .id = 0x59, 172*91f16700Schasinglulu .name = "XCZU17EG", 173*91f16700Schasinglulu }, 174*91f16700Schasinglulu { 175*91f16700Schasinglulu .id = 0x60, 176*91f16700Schasinglulu .name = "XCZU28DR", 177*91f16700Schasinglulu }, 178*91f16700Schasinglulu { 179*91f16700Schasinglulu .id = 0x61, 180*91f16700Schasinglulu .name = "XCZU21DR", 181*91f16700Schasinglulu }, 182*91f16700Schasinglulu { 183*91f16700Schasinglulu .id = 0x62, 184*91f16700Schasinglulu .name = "XCZU29DR", 185*91f16700Schasinglulu }, 186*91f16700Schasinglulu { 187*91f16700Schasinglulu .id = 0x63, 188*91f16700Schasinglulu .name = "XCZU23DR", 189*91f16700Schasinglulu }, 190*91f16700Schasinglulu { 191*91f16700Schasinglulu .id = 0x64, 192*91f16700Schasinglulu .name = "XCZU27DR", 193*91f16700Schasinglulu }, 194*91f16700Schasinglulu { 195*91f16700Schasinglulu .id = 0x65, 196*91f16700Schasinglulu .name = "XCZU25DR", 197*91f16700Schasinglulu }, 198*91f16700Schasinglulu { 199*91f16700Schasinglulu .id = 0x66, 200*91f16700Schasinglulu .name = "XCZU39DR", 201*91f16700Schasinglulu }, 202*91f16700Schasinglulu { 203*91f16700Schasinglulu .id = 0x7d, 204*91f16700Schasinglulu .name = "XCZU43DR", 205*91f16700Schasinglulu }, 206*91f16700Schasinglulu { 207*91f16700Schasinglulu .id = 0x78, 208*91f16700Schasinglulu .name = "XCZU46DR", 209*91f16700Schasinglulu }, 210*91f16700Schasinglulu { 211*91f16700Schasinglulu .id = 0x7f, 212*91f16700Schasinglulu .name = "XCZU47DR", 213*91f16700Schasinglulu }, 214*91f16700Schasinglulu { 215*91f16700Schasinglulu .id = 0x7b, 216*91f16700Schasinglulu .name = "XCZU48DR", 217*91f16700Schasinglulu }, 218*91f16700Schasinglulu { 219*91f16700Schasinglulu .id = 0x7e, 220*91f16700Schasinglulu .name = "XCZU49DR", 221*91f16700Schasinglulu }, 222*91f16700Schasinglulu }; 223*91f16700Schasinglulu 224*91f16700Schasinglulu #define ZYNQMP_PL_STATUS_BIT 9 225*91f16700Schasinglulu #define ZYNQMP_PL_STATUS_MASK BIT(ZYNQMP_PL_STATUS_BIT) 226*91f16700Schasinglulu #define ZYNQMP_CSU_VERSION_MASK ~(ZYNQMP_PL_STATUS_MASK) 227*91f16700Schasinglulu 228*91f16700Schasinglulu #define SILICON_ID_XCK24 0x4712093U 229*91f16700Schasinglulu #define SILICON_ID_XCK26 0x4724093U 230*91f16700Schasinglulu 231*91f16700Schasinglulu static char *zynqmp_get_silicon_idcode_name(void) 232*91f16700Schasinglulu { 233*91f16700Schasinglulu uint32_t id, ver, chipid[2]; 234*91f16700Schasinglulu size_t i, j, len; 235*91f16700Schasinglulu const char *name = "EG/EV"; 236*91f16700Schasinglulu 237*91f16700Schasinglulu if (pm_get_chipid(chipid) != PM_RET_SUCCESS) { 238*91f16700Schasinglulu return "XCZUUNKN"; 239*91f16700Schasinglulu } 240*91f16700Schasinglulu 241*91f16700Schasinglulu id = chipid[0] & (ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | 242*91f16700Schasinglulu ZYNQMP_CSU_IDCODE_SVD_MASK); 243*91f16700Schasinglulu id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT; 244*91f16700Schasinglulu ver = chipid[1] >> ZYNQMP_EFUSE_IPDISABLE_SHIFT; 245*91f16700Schasinglulu 246*91f16700Schasinglulu for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { 247*91f16700Schasinglulu if (zynqmp_devices[i].id == id && 248*91f16700Schasinglulu zynqmp_devices[i].ver == (ver & ZYNQMP_CSU_VERSION_MASK)) { 249*91f16700Schasinglulu break; 250*91f16700Schasinglulu } 251*91f16700Schasinglulu } 252*91f16700Schasinglulu 253*91f16700Schasinglulu if (i >= ARRAY_SIZE(zynqmp_devices)) { 254*91f16700Schasinglulu switch (chipid[0]) { 255*91f16700Schasinglulu case SILICON_ID_XCK24: 256*91f16700Schasinglulu return "XCK24"; 257*91f16700Schasinglulu case SILICON_ID_XCK26: 258*91f16700Schasinglulu return "XCK26"; 259*91f16700Schasinglulu default: 260*91f16700Schasinglulu return "XCZUUNKN"; 261*91f16700Schasinglulu } 262*91f16700Schasinglulu } 263*91f16700Schasinglulu 264*91f16700Schasinglulu if (!zynqmp_devices[i].evexists) { 265*91f16700Schasinglulu return zynqmp_devices[i].name; 266*91f16700Schasinglulu } 267*91f16700Schasinglulu 268*91f16700Schasinglulu if ((ver & ZYNQMP_PL_STATUS_MASK) != 0U) { 269*91f16700Schasinglulu return zynqmp_devices[i].name; 270*91f16700Schasinglulu } 271*91f16700Schasinglulu 272*91f16700Schasinglulu len = strlen(zynqmp_devices[i].name) - 2; 273*91f16700Schasinglulu for (j = 0; j < strlen(name); j++) { 274*91f16700Schasinglulu zynqmp_devices[i].name[len] = name[j]; 275*91f16700Schasinglulu len++; 276*91f16700Schasinglulu } 277*91f16700Schasinglulu zynqmp_devices[i].name[len] = '\0'; 278*91f16700Schasinglulu 279*91f16700Schasinglulu return zynqmp_devices[i].name; 280*91f16700Schasinglulu } 281*91f16700Schasinglulu 282*91f16700Schasinglulu static unsigned int zynqmp_get_rtl_ver(void) 283*91f16700Schasinglulu { 284*91f16700Schasinglulu uint32_t ver; 285*91f16700Schasinglulu 286*91f16700Schasinglulu ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); 287*91f16700Schasinglulu ver &= ZYNQMP_RTL_VER_MASK; 288*91f16700Schasinglulu ver >>= ZYNQMP_RTL_VER_SHIFT; 289*91f16700Schasinglulu 290*91f16700Schasinglulu return ver; 291*91f16700Schasinglulu } 292*91f16700Schasinglulu 293*91f16700Schasinglulu static char *zynqmp_print_silicon_idcode(void) 294*91f16700Schasinglulu { 295*91f16700Schasinglulu uint32_t id, maskid, tmp; 296*91f16700Schasinglulu 297*91f16700Schasinglulu id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); 298*91f16700Schasinglulu 299*91f16700Schasinglulu tmp = id; 300*91f16700Schasinglulu tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK | 301*91f16700Schasinglulu ZYNQMP_CSU_IDCODE_FAMILY_MASK; 302*91f16700Schasinglulu maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT | 303*91f16700Schasinglulu ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT; 304*91f16700Schasinglulu if (tmp != maskid) { 305*91f16700Schasinglulu ERROR("Incorrect IDCODE 0x%x, maskid 0x%x\n", id, maskid); 306*91f16700Schasinglulu return "UNKN"; 307*91f16700Schasinglulu } 308*91f16700Schasinglulu VERBOSE("IDCODE 0x%x\n", id); 309*91f16700Schasinglulu return zynqmp_get_silicon_idcode_name(); 310*91f16700Schasinglulu } 311*91f16700Schasinglulu 312*91f16700Schasinglulu int32_t plat_is_smccc_feature_available(u_register_t fid) 313*91f16700Schasinglulu { 314*91f16700Schasinglulu switch (fid) { 315*91f16700Schasinglulu case SMCCC_ARCH_SOC_ID: 316*91f16700Schasinglulu return SMC_ARCH_CALL_SUCCESS; 317*91f16700Schasinglulu default: 318*91f16700Schasinglulu return SMC_ARCH_CALL_NOT_SUPPORTED; 319*91f16700Schasinglulu } 320*91f16700Schasinglulu 321*91f16700Schasinglulu return SMC_ARCH_CALL_NOT_SUPPORTED; 322*91f16700Schasinglulu } 323*91f16700Schasinglulu 324*91f16700Schasinglulu int32_t plat_get_soc_version(void) 325*91f16700Schasinglulu { 326*91f16700Schasinglulu uint32_t chip_id = zynqmp_get_silicon_ver(); 327*91f16700Schasinglulu uint32_t manfid = SOC_ID_SET_JEP_106(JEDEC_XILINX_BKID, JEDEC_XILINX_MFID); 328*91f16700Schasinglulu 329*91f16700Schasinglulu return (int32_t)(manfid | (chip_id & 0xFFFF)); 330*91f16700Schasinglulu } 331*91f16700Schasinglulu 332*91f16700Schasinglulu int32_t plat_get_soc_revision(void) 333*91f16700Schasinglulu { 334*91f16700Schasinglulu return mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); 335*91f16700Schasinglulu } 336*91f16700Schasinglulu 337*91f16700Schasinglulu static uint32_t zynqmp_get_ps_ver(void) 338*91f16700Schasinglulu { 339*91f16700Schasinglulu uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); 340*91f16700Schasinglulu 341*91f16700Schasinglulu ver &= ZYNQMP_PS_VER_MASK; 342*91f16700Schasinglulu ver >>= ZYNQMP_PS_VER_SHIFT; 343*91f16700Schasinglulu 344*91f16700Schasinglulu return ver + 1U; 345*91f16700Schasinglulu } 346*91f16700Schasinglulu 347*91f16700Schasinglulu static void zynqmp_print_platform_name(void) 348*91f16700Schasinglulu { 349*91f16700Schasinglulu uint32_t ver = zynqmp_get_silicon_ver(); 350*91f16700Schasinglulu uint32_t rtl = zynqmp_get_rtl_ver(); 351*91f16700Schasinglulu char *label = "Unknown"; 352*91f16700Schasinglulu 353*91f16700Schasinglulu switch (ver) { 354*91f16700Schasinglulu case ZYNQMP_CSU_VERSION_QEMU: 355*91f16700Schasinglulu label = "QEMU"; 356*91f16700Schasinglulu break; 357*91f16700Schasinglulu case ZYNQMP_CSU_VERSION_SILICON: 358*91f16700Schasinglulu label = "silicon"; 359*91f16700Schasinglulu break; 360*91f16700Schasinglulu default: 361*91f16700Schasinglulu /* Do nothing in default case */ 362*91f16700Schasinglulu break; 363*91f16700Schasinglulu } 364*91f16700Schasinglulu 365*91f16700Schasinglulu VERBOSE("TF-A running on %s/%s at 0x%x\n", 366*91f16700Schasinglulu zynqmp_print_silicon_idcode(), label, BL31_BASE); 367*91f16700Schasinglulu VERBOSE("TF-A running on v%d/RTL%d.%d\n", 368*91f16700Schasinglulu zynqmp_get_ps_ver(), (rtl & 0xf0) >> 4, rtl & 0xf); 369*91f16700Schasinglulu } 370*91f16700Schasinglulu #else 371*91f16700Schasinglulu static inline void zynqmp_print_platform_name(void) { } 372*91f16700Schasinglulu #endif 373*91f16700Schasinglulu 374*91f16700Schasinglulu uint32_t zynqmp_get_bootmode(void) 375*91f16700Schasinglulu { 376*91f16700Schasinglulu uint32_t r; 377*91f16700Schasinglulu unsigned int ret; 378*91f16700Schasinglulu 379*91f16700Schasinglulu ret = pm_mmio_read(CRL_APB_BOOT_MODE_USER, &r); 380*91f16700Schasinglulu 381*91f16700Schasinglulu if (ret != PM_RET_SUCCESS) { 382*91f16700Schasinglulu r = mmio_read_32(CRL_APB_BOOT_MODE_USER); 383*91f16700Schasinglulu } 384*91f16700Schasinglulu 385*91f16700Schasinglulu return r & CRL_APB_BOOT_MODE_MASK; 386*91f16700Schasinglulu } 387*91f16700Schasinglulu 388*91f16700Schasinglulu void zynqmp_config_setup(void) 389*91f16700Schasinglulu { 390*91f16700Schasinglulu uint64_t counter_freq; 391*91f16700Schasinglulu 392*91f16700Schasinglulu /* Configure IPI data for ZynqMP */ 393*91f16700Schasinglulu zynqmp_ipi_config_table_init(); 394*91f16700Schasinglulu 395*91f16700Schasinglulu zynqmp_print_platform_name(); 396*91f16700Schasinglulu 397*91f16700Schasinglulu /* Configure counter frequency */ 398*91f16700Schasinglulu counter_freq = read_cntfrq_el0(); 399*91f16700Schasinglulu if (counter_freq == ZYNQMP_DEFAULT_COUNTER_FREQ) { 400*91f16700Schasinglulu write_cntfrq_el0(plat_get_syscnt_freq2()); 401*91f16700Schasinglulu } 402*91f16700Schasinglulu 403*91f16700Schasinglulu generic_delay_timer_init(); 404*91f16700Schasinglulu } 405*91f16700Schasinglulu 406*91f16700Schasinglulu uint32_t plat_get_syscnt_freq2(void) 407*91f16700Schasinglulu { 408*91f16700Schasinglulu uint32_t ver = zynqmp_get_silicon_ver(); 409*91f16700Schasinglulu 410*91f16700Schasinglulu if (ver == ZYNQMP_CSU_VERSION_QEMU) { 411*91f16700Schasinglulu return 65000000; 412*91f16700Schasinglulu } else { 413*91f16700Schasinglulu return mmio_read_32(IOU_SCNTRS_BASEFREQ); 414*91f16700Schasinglulu } 415*91f16700Schasinglulu } 416