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