diff --git a/changelog.yaml b/changelog.yaml index 7d8760eac..fd2a8ecc2 100644 --- a/changelog.yaml +++ b/changelog.yaml @@ -677,6 +677,13 @@ subsections: - plat/zynqmp - plat/xilinx/zynqmp + - title: AMD + scope: amd + + subsections: + - title: Versal Gen 2 + scope: versal2 + - title: Nuvoton scope: nuvoton diff --git a/docs/plat/amd-versal2.rst b/docs/plat/amd-versal2.rst new file mode 100644 index 000000000..876ab3c72 --- /dev/null +++ b/docs/plat/amd-versal2.rst @@ -0,0 +1,87 @@ +AMD Versal Gen 2 +================ + +Trusted Firmware-A implements the EL3 firmware layer for AMD Versal Gen 2. +The platform only uses the runtime part of TF-A as AMD Versal Gen 2 already +has a BootROM (BL1) and PMC FW (BL2). + +BL31 is TF-A. +BL32 is an optional Secure Payload. +BL33 is the non-secure world software (U-Boot, Linux etc). + +To build: +```bash +make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal2 bl31 +``` + +To build TF-A for JTAG DCC console: +```bash +make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal2 CONSOLE=dcc bl31 +``` + +To build TF-A with Errata management interface +```bash +make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal2 bl31 ERRATA_ABI_SUPPORT=1 +``` + +To build TF-A with IPI CRC check: +```bash +make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal2 bl31 IPI_CRC_CHECK=1 +``` + +AMD Versal Gen 2 platform specific build options +------------------------------------------------- + +* `MEM_BASE`: Specifies the base address of the bl31 binary. +* `MEM_SIZE`: Specifies the size of the memory region of the bl31 binary. +* `BL32_MEM_BASE`: Specifies the base address of the bl32 binary. +* `BL32_MEM_SIZE`: Specifies the size of the memory region of the bl32 binary. + +* `CONSOLE`: Select the console driver. Options: + - `pl011`, `pl011_0`: ARM pl011 UART 0 (default) + - `pl011_1` : ARM pl011 UART 1 + - `dcc` : JTAG Debug Communication Channel(DCC) + + +Reference DEN0028E SMC calling convention +------------------------------------------ + +Allocated subranges of Function Identifier to SIP services +------------------------------------------------------------ + ++-----------------------+-------------------------------------------------------+ +| SMC Function | Identifier Service type | ++-----------------------+-------------------------------------------------------+ +| 0xC2000000-0xC200FFFF | Fast SMC64 SiP Service Calls as per SMCCC Section 6.1 | ++-----------------------+-------------------------------------------------------+ + +IPI SMC call ranges +------------------- + ++---------------------------+-----------------------------------------------------------+ +| SMC Function Identifier | Service type | ++---------------------------+-----------------------------------------------------------+ +| 0xc2001000-0xc2001FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI | ++---------------------------+-----------------------------------------------------------+ + +PM SMC call ranges +------------------ + ++---------------------------+---------------------------------------------------------------------------+ +| SMC Function Identifier | Service type | ++---------------------------+---------------------------------------------------------------------------+ +| 0xc2000000-0xc2000FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management | ++---------------------------+---------------------------------------------------------------------------+ + +SMC function IDs for SiP Service queries +---------------------------------------- + ++--------------+--------------+--------------+ +| Service | Call UID | Revision | ++--------------+--------------+--------------+ +| SiP Service | 0x8200_FF01 | 0x8200_FF03 | ++--------------+--------------+--------------+ + +Call UID Query – Returns a unique identifier of the service provider. + +Revision Query – Returns revision details of the service implementor. diff --git a/docs/plat/index.rst b/docs/plat/index.rst index 5c1ded03c..85c97e527 100644 --- a/docs/plat/index.rst +++ b/docs/plat/index.rst @@ -7,6 +7,7 @@ Platform Ports :hidden: allwinner + amd-versal2 arm/index ast2700 meson-axg diff --git a/plat/amd/versal2/aarch64/common.c b/plat/amd/versal2/aarch64/common.c new file mode 100644 index 000000000..3ab3dca99 --- /dev/null +++ b/plat/amd/versal2/aarch64/common.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +uint32_t platform_id, platform_version; + +/* + * Table of regions to map using the MMU. + * This doesn't include TZRAM as the 'mem_layout' argument passed to + * configure_mmu_elx() will give the available subset of that, + */ +const mmap_region_t plat_mmap[] = { + MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(IPI_BASE, IPI_SIZE, MT_DEVICE | MT_RW | MT_SECURE), +#if defined(TRANSFER_LIST) + MAP_REGION_FLAT(FW_HANDOFF_BASE, FW_HANDOFF_BASE + FW_HANDOFF_SIZE, + MT_MEMORY | MT_RW | MT_NS), +#endif + { 0 } +}; + +const mmap_region_t *plat_get_mmap(void) +{ + return plat_mmap; +} + +/* For saving cpu clock for certain platform */ +uint32_t cpu_clock; + +const char *board_name_decode(void) +{ + const char *platform; + + switch (platform_id) { + case SPP: + platform = "IPP"; + break; + case EMU: + platform = "EMU"; + break; + case SILICON: + platform = "Silicon"; + break; + case QEMU: + platform = "QEMU"; + break; + default: + platform = "Unknown"; + } + + return platform; +} + +void board_detection(void) +{ + uint32_t version; + + version = mmio_read_32(PMC_TAP_VERSION); + platform_id = FIELD_GET(PLATFORM_MASK, version); + platform_version = FIELD_GET(PLATFORM_VERSION_MASK, version); + + if (platform_id == QEMU_COSIM) { + platform_id = QEMU; + } + + /* Make sure that console is setup to see this message */ + VERBOSE("Platform id: %d version: %d.%d\n", platform_id, + platform_version / 10U, platform_version % 10U); +} + +uint32_t get_uart_clk(void) +{ + uint32_t uart_clock = 0; + + switch (platform_id) { + case SPP: + case SPP_MMD: + uart_clock = cpu_clock; + break; + case EMU: + case EMU_MMD: + uart_clock = 25000000; + break; + case QEMU: + /* Random values now */ + uart_clock = 25000000; + break; + case SILICON: + uart_clock = 100000000; + break; + default: + panic(); + } + + return uart_clock; +} + +void config_setup(void) +{ + uint32_t val; + uintptr_t crl_base, iou_scntrs_base, psx_base; + + crl_base = CRL; + iou_scntrs_base = IOU_SCNTRS; + psx_base = PSX_CRF; + + /* Reset for system timestamp generator in FPX */ + mmio_write_32(psx_base + PSX_CRF_RST_TIMESTAMP_OFFSET, 0); + + /* Global timer init - Program time stamp reference clk */ + val = mmio_read_32(crl_base + CRL_TIMESTAMP_REF_CTRL_OFFSET); + val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT; + mmio_write_32(crl_base + CRL_TIMESTAMP_REF_CTRL_OFFSET, val); + + /* Clear reset of timestamp reg */ + mmio_write_32(crl_base + CRL_RST_TIMESTAMP_OFFSET, 0); + + /* Program freq register in System counter and enable system counter. */ + mmio_write_32(iou_scntrs_base + IOU_SCNTRS_BASE_FREQ_OFFSET, + cpu_clock); + mmio_write_32(iou_scntrs_base + IOU_SCNTRS_COUNTER_CONTROL_REG_OFFSET, + IOU_SCNTRS_CONTROL_EN); + + generic_delay_timer_init(); + + /* Configure IPI data */ + soc_ipi_config_table_init(); +} + +uint32_t plat_get_syscnt_freq2(void) +{ + return cpu_clock; +} diff --git a/plat/amd/versal2/aarch64/helpers.S b/plat/amd/versal2/aarch64/helpers.S new file mode 100644 index 000000000..580bb764a --- /dev/null +++ b/plat/amd/versal2/aarch64/helpers.S @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include + + .globl plat_secondary_cold_boot_setup + .globl plat_is_my_cpu_primary + .globl platform_mem_init + .globl plat_my_core_pos + + /* ----------------------------------------------------- + * void plat_secondary_cold_boot_setup (void); + * + * This function performs any platform specific actions + * needed for a secondary cpu after a cold reset e.g + * mark the cpu's presence, mechanism to place it in a + * holding pen etc. + * TODO: Should we read the PSYS register to make sure + * that the request has gone through. + * ----------------------------------------------------- + */ +func plat_secondary_cold_boot_setup + mrs x0, mpidr_el1 + + /* + * There is no sane reason to come out of this wfi. This + * cpu will be powered on and reset by the cpu_on pm api + */ + dsb sy + bl plat_panic_handler +endfunc plat_secondary_cold_boot_setup + +func plat_is_my_cpu_primary + mov x9, x30 + bl plat_my_core_pos + cmp x0, #PRIMARY_CPU + cset x0, eq + ret x9 +endfunc plat_is_my_cpu_primary + + /* ----------------------------------------------------- + * unsigned int plat_my_core_pos(void) + * This function uses the plat_core_pos_by_mpidr() + * definition to get the index of the calling CPU. + * ----------------------------------------------------- + */ +func plat_my_core_pos + mrs x0, mpidr_el1 + b plat_core_pos_by_mpidr +endfunc plat_my_core_pos + + /* --------------------------------------------------------------------- + * We don't need to carry out any memory initialization on platform + * The Secure RAM is accessible straight away. + * --------------------------------------------------------------------- + */ +func platform_mem_init + ret +endfunc platform_mem_init diff --git a/plat/amd/versal2/bl31_setup.c b/plat/amd/versal2/bl31_setup.c new file mode 100644 index 000000000..e878863ab --- /dev/null +++ b/plat/amd/versal2/bl31_setup.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; + +/* + * Return a pointer to the 'entry_point_info' structure of the next image for + * the security state specified. BL33 corresponds to the non-secure image type + * while BL32 corresponds to the secure image type. A NULL pointer is returned + * if the image does not exist. + */ +entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) +{ + assert(sec_state_is_valid(type)); + + if (type == NON_SECURE) { + return &bl33_image_ep_info; + } + + return &bl32_image_ep_info; +} + +/* + * Set the build time defaults,if we can't find any config data. + */ +static inline void bl31_set_default_config(void) +{ + bl32_image_ep_info.pc = BL32_BASE; + bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry(); +#if defined(SPD_opteed) + /* NS dtb addr passed to optee_os */ + bl32_image_ep_info.args.arg3 = XILINX_OF_BOARD_DTB_ADDR; +#endif + bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); + bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); +} + +/* + * Perform any BL31 specific platform actions. Here is an opportunity to copy + * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they + * are lost (potentially). This needs to be done before the MMU is initialized + * so that the memory layout can be used while creating page tables. + */ +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + uint32_t uart_clock; + int32_t rc; + + board_detection(); + + /* FIXME */ + switch (platform_id) { + case SPP: + switch (platform_version) { + case SPP_PSXC_MMI_V2_0: + cpu_clock = 770000; + break; + case SPP_PSXC_MMI_V3_0: + cpu_clock = 908000; + break; + default: + panic(); + } + break; + case SPP_MMD: + switch (platform_version) { + case SPP_PSXC_ISP_AIE_V2_0: + case SPP_PSXC_MMD_AIE_FRZ_EA: + case SPP_PSXC_MMD_AIE_V3_0: + cpu_clock = 760000; + break; + default: + panic(); + } + break; + case EMU: + case EMU_MMD: + cpu_clock = 112203; + break; + case QEMU: + /* Random values now */ + cpu_clock = 3333333; + break; + case SILICON: + cpu_clock = 100000000; + break; + default: + panic(); + } + + uart_clock = get_uart_clk(); + + if (CONSOLE_IS(pl011_0) || CONSOLE_IS(pl011_1)) { + static console_t _runtime_console; + + /* Initialize the console to provide early debug support */ + rc = console_pl011_register(UART_BASE, uart_clock, + UART_BAUDRATE, + &_runtime_console); + if (rc == 0) { + panic(); + } + + console_set_scope(&_runtime_console, CONSOLE_FLAG_BOOT | + CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH); + } else if (CONSOLE_IS(dcc)) { + /* Initialize the dcc console for debug. + * dcc is over jtag and does not configures uart0 or uart1. + */ + rc = console_dcc_register(); + if (rc == 0) { + panic(); + } + } else { + /* Making MISRA C 2012 15.7 compliant */ + } + + NOTICE("TF-A running on %s %d.%d\n", board_name_decode(), + platform_version / 10U, platform_version % 10U); + + /* Initialize the platform config for future decision making */ + config_setup(); + + /* + * Do initial security configuration to allow DRAM/device access. On + * Base only DRAM security is programmable (via TrustZone), but + * other platforms might have more programmable security devices + * present. + */ + + /* Populate common information for BL32 and BL33 */ + SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); + SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); + SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + bl31_set_default_config(); + + long rev_var = cpu_get_rev_var(); + + INFO("CPU Revision = 0x%lx\n", rev_var); + INFO("cpu_clock = %dHz, uart_clock = %dHz\n", cpu_clock, uart_clock); + NOTICE("BL31: Executing from 0x%x\n", BL31_BASE); + NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc); + NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc); + +} + +static versal_intr_info_type_el3_t type_el3_interrupt_table[MAX_INTR_EL3]; + +int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler) +{ + static uint32_t index; + uint32_t i; + + /* Validate 'handler' and 'id' parameters */ + if (handler == NULL || index >= MAX_INTR_EL3) { + return -EINVAL; + } + + /* Check if a handler has already been registered */ + for (i = 0; i < index; i++) { + if (id == type_el3_interrupt_table[i].id) { + return -EALREADY; + } + } + + type_el3_interrupt_table[index].id = id; + type_el3_interrupt_table[index].handler = handler; + + index++; + + return 0; +} + +static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags, + void *handle, void *cookie) +{ + uint32_t intr_id; + uint32_t i; + interrupt_type_handler_t handler = NULL; + + intr_id = plat_ic_get_pending_interrupt_id(); + + for (i = 0; i < MAX_INTR_EL3; i++) { + if (intr_id == type_el3_interrupt_table[i].id) { + handler = type_el3_interrupt_table[i].handler; + } + } + + if (handler != NULL) { + (void)handler(intr_id, flags, handle, cookie); + } + + return 0; +} + +void bl31_platform_setup(void) +{ + prepare_dtb(); + + /* Initialize the gic cpu and distributor interfaces */ + plat_gic_driver_init(); + plat_gic_init(); + + if (platform_id != EMU) { + init_scmi_server(); + } +} + +void bl31_plat_runtime_setup(void) +{ + uint64_t flags = 0; + int32_t rc; + + set_interrupt_rm_flag(flags, NON_SECURE); + rc = register_interrupt_type_handler(INTR_TYPE_EL3, + rdo_el3_interrupt_handler, flags); + if (rc != 0) { + panic(); + } +} + +/* + * Perform the very early platform specific architectural setup here. + */ +void bl31_plat_arch_setup(void) +{ + const mmap_region_t bl_regions[] = { +#if (defined(XILINX_OF_BOARD_DTB_ADDR) && !IS_TFA_IN_OCM(BL31_BASE)) + MAP_REGION_FLAT(XILINX_OF_BOARD_DTB_ADDR, XILINX_OF_BOARD_DTB_MAX_SIZE, + MT_MEMORY | MT_RW | MT_NS), +#endif + MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE, + MT_MEMORY | MT_RW | MT_SECURE), + MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, + MT_CODE | MT_SECURE), + MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, + MT_RO_DATA | MT_SECURE), + MAP_REGION_FLAT(SMT_BUFFER_BASE, 0x1000, + MT_DEVICE | MT_RW | MT_NON_CACHEABLE | MT_EXECUTE_NEVER | MT_NS), + {0} + }; + + setup_page_tables(bl_regions, plat_get_mmap()); + enable_mmu(0); +} diff --git a/plat/amd/versal2/gicv3.c b/plat/amd/versal2/gicv3.c new file mode 100644 index 000000000..c7b44e166 --- /dev/null +++ b/plat/amd/versal2/gicv3.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include + +/****************************************************************************** + * The following functions are defined as weak to allow a platform to override + * the way the GICv3 driver is initialised and used. + *****************************************************************************/ +#pragma weak plat_gic_driver_init +#pragma weak plat_gic_init +#pragma weak plat_gic_cpuif_enable +#pragma weak plat_gic_cpuif_disable +#pragma weak plat_gic_pcpu_init +#pragma weak plat_gic_redistif_on +#pragma weak plat_gic_redistif_off + +/* The GICv3 driver only needs to be initialized in EL3 */ +static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; + +static const interrupt_prop_t _interrupt_props[] = { + PLAT_G1S_IRQ_PROPS(INTR_GROUP1S), + PLAT_G0_IRQ_PROPS(INTR_GROUP0) +}; + +/* + * We save and restore the GICv3 context on system suspend. Allocate the + * data in the designated EL3 Secure carve-out memory. + */ +static gicv3_redist_ctx_t rdist_ctx __section("._el3_tzc_dram"); +static gicv3_dist_ctx_t dist_ctx __section("._el3_tzc_dram"); + +/* + * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register + * to core position. + * + * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity + * values read from GICR_TYPER don't have an MT field. To reuse the same + * translation used for CPUs, we insert MT bit read from the PE's MPIDR into + * that read from GICR_TYPER. + * + * Assumptions: + * + * - All CPUs implemented in the system have MPIDR_EL1.MT bit set; + * - No CPUs implemented in the system use affinity level 3. + */ +static uint32_t _gicv3_mpidr_hash(u_register_t mpidr) +{ + mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK); + return plat_core_pos_by_mpidr(mpidr); +} + +static const gicv3_driver_data_t _gic_data __unused = { + .gicd_base = PLAT_GICD_BASE_VALUE, + .gicr_base = PLAT_GICR_BASE_VALUE, + .interrupt_props = _interrupt_props, + .interrupt_props_num = ARRAY_SIZE(_interrupt_props), + .rdistif_num = PLATFORM_CORE_COUNT, + .rdistif_base_addrs = rdistif_base_addrs, + .mpidr_to_core_pos = _gicv3_mpidr_hash +}; + +void __init plat_gic_driver_init(void) +{ + /* + * The GICv3 driver is initialized in EL3 and does not need + * to be initialized again in SEL1. This is because the S-EL1 + * can use GIC system registers to manage interrupts and does + * not need GIC interface base addresses to be configured. + */ +#if IMAGE_BL31 + gicv3_driver_init(&_gic_data); +#endif +} + +/****************************************************************************** + * common helper to initialize the GIC. Only invoked by BL31 + *****************************************************************************/ +void __init plat_gic_init(void) +{ + gicv3_distif_init(); + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} + +/****************************************************************************** + * common helper to enable the GIC CPU interface + *****************************************************************************/ +void plat_gic_cpuif_enable(void) +{ + gicv3_cpuif_enable(plat_my_core_pos()); +} + +/****************************************************************************** + * common helper to disable the GIC CPU interface + *****************************************************************************/ +void plat_gic_cpuif_disable(void) +{ + gicv3_cpuif_disable(plat_my_core_pos()); +} + +/****************************************************************************** + * common helper to initialize the per-cpu redistributor interface in GICv3 + *****************************************************************************/ +void plat_gic_pcpu_init(void) +{ + gicv3_rdistif_init(plat_my_core_pos()); +} + +/****************************************************************************** + * common helpers to power GIC redistributor interface + *****************************************************************************/ +void plat_gic_redistif_on(void) +{ + gicv3_rdistif_on(plat_my_core_pos()); +} + +void plat_gic_redistif_off(void) +{ + gicv3_rdistif_off(plat_my_core_pos()); +} + +/****************************************************************************** + * common helper to save & restore the GICv3 on resume from system suspend + *****************************************************************************/ +void plat_gic_save(void) +{ + /* + * If an ITS is available, save its context before + * the Redistributor using: + * gicv3_its_save_disable(gits_base, &its_ctx[i]) + * Additionnaly, an implementation-defined sequence may + * be required to save the whole ITS state. + */ + + /* + * Save the GIC Redistributors and ITS contexts before the + * Distributor context. As we only handle SYSTEM SUSPEND API, + * we only need to save the context of the CPU that is issuing + * the SYSTEM SUSPEND call, i.e. the current CPU. + */ + gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx); + + /* Save the GIC Distributor context */ + gicv3_distif_save(&dist_ctx); + + /* + * From here, all the components of the GIC can be safely powered down + * as long as there is an alternate way to handle wakeup interrupt + * sources. + */ +} + +void plat_gic_resume(void) +{ + /* Restore the GIC Distributor context */ + gicv3_distif_init_restore(&dist_ctx); + + /* + * Restore the GIC Redistributor and ITS contexts after the + * Distributor context. As we only handle SYSTEM SUSPEND API, + * we only need to restore the context of the CPU that issued + * the SYSTEM SUSPEND call. + */ + gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx); + + /* + * If an ITS is available, restore its context after + * the Redistributor using: + * gicv3_its_restore(gits_base, &its_ctx[i]) + * An implementation-defined sequence may be required to + * restore the whole ITS state. The ITS must also be + * re-enabled after this sequence has been executed. + */ +} diff --git a/plat/amd/versal2/include/def.h b/plat/amd/versal2/include/def.h new file mode 100644 index 000000000..a8cbaafb8 --- /dev/null +++ b/plat/amd/versal2/include/def.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef DEF_H +#define DEF_H + +#include +#include + +#define MAX_INTR_EL3 2 + +/* List all consoles */ +#define CONSOLE_ID_pl011 U(1) +#define CONSOLE_ID_pl011_0 U(1) +#define CONSOLE_ID_pl011_1 U(2) +#define CONSOLE_ID_dcc U(3) + +#define CONSOLE_IS(con) (CONSOLE_ID_ ## con == CONSOLE) + +/* List all platforms */ +#define SILICON U(0) +#define SPP U(1) +#define EMU U(2) +#define QEMU U(3) +#define SPP_MMD U(5) +#define EMU_MMD U(6) +#define QEMU_COSIM U(7) + +/* For platform detection */ +#define PMC_TAP U(0xF11A0000) +#define PMC_TAP_VERSION (PMC_TAP + 0x4U) +# define PLATFORM_MASK GENMASK(27U, 24U) +# define PLATFORM_VERSION_MASK GENMASK(31U, 28U) + +/* Global timer reset */ +#define PSX_CRF U(0xEC200000) +#define ACPU0_CLK_CTRL U(0x10C) +#define ACPU_CLK_CTRL_CLKACT BIT(25) + +#define RST_APU0_OFFSET U(0x300) +#define RST_APU_COLD_RESET BIT(0) +#define RST_APU_WARN_RESET BIT(4) +#define RST_APU_CLUSTER_COLD_RESET BIT(8) +#define RST_APU_CLUSTER_WARM_RESET BIT(9) + +#define PSX_CRF_RST_TIMESTAMP_OFFSET U(0x33C) + +#define APU_PCLI (0xECB10000ULL) +#define APU_PCLI_CPU_STEP (0x30ULL) +#define APU_PCLI_CLUSTER_CPU_STEP (4ULL * APU_PCLI_CPU_STEP) +#define APU_PCLI_CLUSTER_OFFSET U(0x8000) +#define APU_PCLI_CLUSTER_STEP U(0x1000) +#define PCLI_PREQ_OFFSET U(0x4) +#define PREQ_CHANGE_REQUEST BIT(0) +#define PCLI_PSTATE_OFFSET U(0x8) +#define PCLI_PSTATE_VAL_SET U(0x48) +#define PCLI_PSTATE_VAL_CLEAR U(0x38) + +/* Firmware Image Package */ +#define PRIMARY_CPU U(0) + +#define CORE_0_ISR_WAKE_OFFSET (0x00000020ULL) +#define APU_PCIL_CORE_X_ISR_WAKE_REG(cpu_id) (APU_PCLI + (CORE_0_ISR_WAKE_OFFSET + \ + (APU_PCLI_CPU_STEP * (cpu_id)))) +#define APU_PCIL_CORE_X_ISR_WAKE_MASK (0x00000001U) +#define CORE_0_IEN_WAKE_OFFSET (0x00000028ULL) +#define APU_PCIL_CORE_X_IEN_WAKE_REG(cpu_id) (APU_PCLI + (CORE_0_IEN_WAKE_OFFSET + \ + (APU_PCLI_CPU_STEP * (cpu_id)))) +#define APU_PCIL_CORE_X_IEN_WAKE_MASK (0x00000001U) +#define CORE_0_IDS_WAKE_OFFSET (0x0000002CULL) +#define APU_PCIL_CORE_X_IDS_WAKE_REG(cpu_id) (APU_PCLI + (CORE_0_IDS_WAKE_OFFSET + \ + (APU_PCLI_CPU_STEP * (cpu_id)))) +#define APU_PCIL_CORE_X_IDS_WAKE_MASK (0x00000001U) +#define CORE_0_ISR_POWER_OFFSET (0x00000010ULL) +#define APU_PCIL_CORE_X_ISR_POWER_REG(cpu_id) (APU_PCLI + (CORE_0_ISR_POWER_OFFSET + \ + (APU_PCLI_CPU_STEP * (cpu_id)))) +#define APU_PCIL_CORE_X_ISR_POWER_MASK U(0x00000001) +#define CORE_0_IEN_POWER_OFFSET (0x00000018ULL) +#define APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id) (APU_PCLI + (CORE_0_IEN_POWER_OFFSET + \ + (APU_PCLI_CPU_STEP * (cpu_id)))) +#define APU_PCIL_CORE_X_IEN_POWER_MASK (0x00000001U) +#define CORE_0_IDS_POWER_OFFSET (0x0000001CULL) +#define APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id) (APU_PCLI + (CORE_0_IDS_POWER_OFFSET + \ + (APU_PCLI_CPU_STEP * (cpu_id)))) +#define APU_PCIL_CORE_X_IDS_POWER_MASK (0x00000001U) +#define CORE_PWRDN_EN_BIT_MASK (0x1U) + +/******************************************************************************* + * memory map related constants + ******************************************************************************/ +/* IPP 1.2/SPP 0.9 mapping */ +#define DEVICE0_BASE U(0xE8000000) /* psx, crl, iou */ +#define DEVICE0_SIZE U(0x08000000) +#define DEVICE1_BASE U(0xE2000000) /* gic */ +#define DEVICE1_SIZE U(0x00800000) +#define DEVICE2_BASE U(0xF1000000) /* uart, pmc_tap */ +#define DEVICE2_SIZE U(0x01000000) +#define CRF_BASE U(0xFD1A0000) +#define CRF_SIZE U(0x00600000) +#define IPI_BASE U(0xEB300000) +#define IPI_SIZE U(0x00100000) + +/* CRL */ +#define CRL U(0xEB5E0000) +#define CRL_TIMESTAMP_REF_CTRL_OFFSET U(0x14C) +#define CRL_RST_TIMESTAMP_OFFSET U(0x348) + +#define CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1U << 25U) + +/* IOU SCNTRS */ +#define IOU_SCNTRS U(0xEC920000) +#define IOU_SCNTRS_COUNTER_CONTROL_REG_OFFSET U(0) +#define IOU_SCNTRS_BASE_FREQ_OFFSET U(0x20) + +#define IOU_SCNTRS_CONTROL_EN U(1) + +#define APU_CLUSTER0 U(0xECC00000) +#define APU_RVBAR_L_0 U(0x40) +#define APU_RVBAR_H_0 U(0x44) +#define APU_CLUSTER_STEP U(0x100000) + +#define SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL U(0xF1060504) + +/******************************************************************************* + * IRQ constants + ******************************************************************************/ +#define IRQ_SEC_PHY_TIMER U(29) + +/******************************************************************************* + * UART related constants + ******************************************************************************/ +#define UART0_BASE U(0xF1920000) +#define UART1_BASE U(0xF1930000) + +#define UART_BAUDRATE 115200 + +#if CONSOLE_IS(pl011_1) +#define UART_BASE UART1_BASE +#else +/* Default console is UART0 */ +#define UART_BASE UART0_BASE +#endif + +#endif /* DEF_H */ diff --git a/plat/amd/versal2/include/plat_ipi.h b/plat/amd/versal2/include/plat_ipi.h new file mode 100644 index 000000000..503ec1fe4 --- /dev/null +++ b/plat/amd/versal2/include/plat_ipi.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* Versal Gen 2 IPI management enums and defines */ + +#ifndef PLAT_IPI_H +#define PLAT_IPI_H + +#include + +#include + +/********************************************************************* + * IPI agent IDs macros + ********************************************************************/ +#define IPI_ID_PMC 1U +#define IPI_ID_APU 2U +#define IPI_ID_RPU0 3U +#define IPI_ID_RPU1 4U +#define IPI_ID_3 5U +#define IPI_ID_4 6U +#define IPI_ID_5 7U +#define IPI_ID_MAX 8U + +/********************************************************************* + * IPI message buffers + ********************************************************************/ +#define IPI_BUFFER_BASEADDR (0xEB3F0000U) + +#define IPI_LOCAL_ID IPI_ID_APU +#define IPI_REMOTE_ID IPI_ID_PMC + +#define IPI_BUFFER_LOCAL_BASE (IPI_BUFFER_BASEADDR + (IPI_LOCAL_ID * 0x200U)) +#define IPI_BUFFER_REMOTE_BASE (IPI_BUFFER_BASEADDR + (IPI_REMOTE_ID * 0x200U)) + +#define IPI_BUFFER_TARGET_LOCAL_OFFSET (IPI_LOCAL_ID * 0x40U) +#define IPI_BUFFER_TARGET_REMOTE_OFFSET (IPI_REMOTE_ID * 0x40U) + +#define IPI_BUFFER_MAX_WORDS 8 + +#define IPI_BUFFER_REQ_OFFSET 0x0U +#define IPI_BUFFER_RESP_OFFSET 0x20U + +/********************************************************************* + * Platform specific IPI API declarations + ********************************************************************/ + +/* Configure IPI table */ +extern void soc_ipi_config_table_init(void); + +/******************************************************************************* + * IPI registers and bitfields + ******************************************************************************/ +#define IPI0_REG_BASE (0xEB330000U) +#define IPI0_TRIG_BIT (1 << 2) +#define PMC_IPI_TRIG_BIT (1 << 1) +#define IPI1_REG_BASE (0xEB340000U) +#define IPI1_TRIG_BIT (1 << 3) +#define IPI2_REG_BASE (0xEB350000U) +#define IPI2_TRIG_BIT (1 << 4) +#define IPI3_REG_BASE (0xEB360000U) +#define IPI3_TRIG_BIT (1 << 5) +#define IPI4_REG_BASE (0xEB370000U) +#define IPI4_TRIG_BIT (1 << 6) +#define IPI5_REG_BASE (0xEB380000U) +#define IPI5_TRIG_BIT (1 << 7) + +#endif /* PLAT_IPI_H */ diff --git a/plat/amd/versal2/include/plat_macros.S b/plat/amd/versal2/include/plat_macros.S new file mode 100644 index 000000000..d20f693db --- /dev/null +++ b/plat/amd/versal2/include/plat_macros.S @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_MACROS_S +#define PLAT_MACROS_S + +#include +#include +#include + +#include "../include/platform_def.h" + +.section .rodata.gic_reg_name, "aS" +/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */ +gicc_regs: + .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" + +/* Applicable only to GICv3 with SRE enabled */ +icc_regs: + .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", "" + +/* Registers common to both GICv2 and GICv3 */ +gicd_pend_reg: + .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n" +newline: + .asciz "\n" +spacer: + .asciz ":\t\t0x" + + /* --------------------------------------------- + * The below utility macro prints out relevant GIC + * registers whenever an unhandled exception is + * taken in BL31 on platform. + * Expects: GICD base in x16, GICC base in x17 + * Clobbers: x0 - x10, sp + * --------------------------------------------- + */ + .macro _print_gic_regs + /* Check for GICv3 system register access */ + mrs x7, id_aa64pfr0_el1 + ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH + cmp x7, #1 + b.ne print_gicv2 + + /* Check for SRE enable */ + mrs x8, ICC_SRE_EL3 + tst x8, #ICC_SRE_SRE_BIT + b.eq print_gicv2 + + /* Load the icc reg list to x6 */ + adr x6, icc_regs + /* Load the icc regs to gp regs used by str_in_crash_buf_print */ + mrs x8, ICC_HPPIR0_EL1 + mrs x9, ICC_HPPIR1_EL1 + mrs x10, ICC_CTLR_EL3 + /* Store to the crash buf and print to console */ + bl str_in_crash_buf_print + b print_gic_common + +print_gicv2: + /* Load the gicc reg list to x6 */ + adr x6, gicc_regs + /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ + ldr w8, [x17, #GICC_HPPIR] + ldr w9, [x17, #GICC_AHPPIR] + ldr w10, [x17, #GICC_CTLR] + /* Store to the crash buf and print to console */ + bl str_in_crash_buf_print + +print_gic_common: + /* Print the GICD_ISPENDR regs */ + add x7, x16, #GICD_ISPENDR + adr x4, gicd_pend_reg + bl asm_print_str +gicd_ispendr_loop: + sub x4, x7, x16 + cmp x4, #0x280 + b.eq exit_print_gic_regs + bl asm_print_hex + + adr x4, spacer + bl asm_print_str + + ldr x4, [x7], #8 + bl asm_print_hex + + adr x4, newline + bl asm_print_str + b gicd_ispendr_loop +exit_print_gic_regs: + .endm + + /* --------------------------------------------- + * The below required platform porting macro + * prints out relevant GIC and CCI registers + * whenever an unhandled exception is taken in + * BL31. + * Clobbers: x0 - x10, x16, x17, sp + * --------------------------------------------- + */ + .macro plat_crash_print_regs + /* + * Empty for now to handle more platforms variant. + * Uncomment it when versions are stable + */ + /* + mov_imm x17, PLAT_GICD_BASE_VALUE + mov_imm x16, PLAT_GICR_BASE_VALUE + _print_gic_regs + */ + .endm + +#endif /* PLAT_MACROS_S */ diff --git a/plat/amd/versal2/include/plat_pm_common.h b/plat/amd/versal2/include/plat_pm_common.h new file mode 100644 index 000000000..5e6847204 --- /dev/null +++ b/plat/amd/versal2/include/plat_pm_common.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Contains platform specific definitions of commonly used macros data types + * for PU Power Management. This file should be common for all PU's. + */ + +#ifndef PLAT_PM_COMMON_H +#define PLAT_PM_COMMON_H + +#include + +#include + +#include "pm_defs.h" + +#define NON_SECURE_FLAG 1U +#define SECURE_FLAG 0U + +#endif /* PLAT_PM_COMMON_H */ diff --git a/plat/amd/versal2/include/plat_private.h b/plat/amd/versal2/include/plat_private.h new file mode 100644 index 000000000..5a2e5bd9f --- /dev/null +++ b/plat/amd/versal2/include/plat_private.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_PRIVATE_H +#define PLAT_PRIVATE_H + +#include +#include + +#define SPP_PSXC_MMI_V2_0 U(6) +#define SPP_PSXC_MMI_V3_0 U(8) + +/* MMD */ +#define SPP_PSXC_ISP_AIE_V2_0 U(3) +#define SPP_PSXC_MMD_AIE_FRZ_EA U(4) +#define SPP_PSXC_MMD_AIE_V3_0 U(5) + +typedef struct versal_intr_info_type_el3 { + uint32_t id; + interrupt_type_handler_t handler; +} versal_intr_info_type_el3_t; + +void config_setup(void); +uint32_t get_uart_clk(void); + +const mmap_region_t *plat_get_mmap(void); + +void plat_gic_driver_init(void); +void plat_gic_init(void); +void plat_gic_cpuif_enable(void); +void plat_gic_cpuif_disable(void); +void plat_gic_pcpu_init(void); +void plat_gic_save(void); +void plat_gic_resume(void); +void plat_gic_redistif_on(void); +void plat_gic_redistif_off(void); + +extern uint32_t cpu_clock, platform_id, platform_version; +void board_detection(void); +const char *board_name_decode(void); +uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, + uint64_t x4, void *cookie, void *handle, uint64_t flags); +int32_t sip_svc_setup_init(void); +/* + * Register handler to specific GIC entrance + * for INTR_TYPE_EL3 type of interrupt + */ +int request_intr_type_el3(uint32_t irq, interrupt_type_handler_t fiq_handler); + +#endif /* PLAT_PRIVATE_H */ diff --git a/plat/amd/versal2/include/platform_def.h b/plat/amd/versal2/include/platform_def.h new file mode 100644 index 000000000..090fe4621 --- /dev/null +++ b/plat/amd/versal2/include/platform_def.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include +#include "def.h" + +/******************************************************************************* + * Generic platform constants + ******************************************************************************/ + +/* Size of cacheable stacks */ +#define PLATFORM_STACK_SIZE U(0x440) + +#define PLATFORM_CLUSTER_COUNT U(4) +#define PLATFORM_CORE_COUNT_PER_CLUSTER U(2) /* 2 CPUs per cluster */ + +#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * PLATFORM_CORE_COUNT_PER_CLUSTER) + +#define PLAT_MAX_PWR_LVL U(2) +#define PLAT_MAX_RET_STATE U(1) +#define PLAT_MAX_OFF_STATE U(2) + +/******************************************************************************* + * BL31 specific defines. + ******************************************************************************/ +/* + * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if + * present). BL31_BASE is calculated using the current BL31 debug size plus a + * little space for growth. + */ +#ifndef MEM_BASE +# define BL31_BASE U(0xBBF00000) +# define BL31_LIMIT U(0xBC000000) +#else +# define BL31_BASE U(MEM_BASE) +# define BL31_LIMIT U(MEM_BASE + MEM_SIZE) +# ifdef MEM_PROGBITS_SIZE +# define BL31_PROGBITS_LIMIT U(MEM_BASE + \ + MEM_PROGBITS_SIZE) +# endif +#endif + +/******************************************************************************* + * BL32 specific defines. + ******************************************************************************/ +#ifndef BL32_MEM_BASE +# define BL32_BASE U(0x60000000) +# define BL32_LIMIT U(0x80000000) +#else +# define BL32_BASE U(BL32_MEM_BASE) +# define BL32_LIMIT U(BL32_MEM_BASE + BL32_MEM_SIZE) +#endif + +/******************************************************************************* + * BL33 specific defines. + ******************************************************************************/ +#ifndef PRELOADED_BL33_BASE +# define PLAT_ARM_NS_IMAGE_BASE U(0x8000000) +#else +# define PLAT_ARM_NS_IMAGE_BASE U(PRELOADED_BL33_BASE) +#endif + +/******************************************************************************* + * TSP specific defines. + ******************************************************************************/ +#define TSP_SEC_MEM_BASE BL32_BASE +#define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE) + +/* ID of the secure physical generic timer interrupt used by the TSP */ +#define ARM_IRQ_SEC_PHY_TIMER U(29) +#define TSP_IRQ_SEC_PHY_TIMER ARM_IRQ_SEC_PHY_TIMER + +/******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ +#define PLAT_DDR_LOWMEM_MAX U(0x80000000) + +#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32U) +#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32U) + +#define XILINX_OF_BOARD_DTB_MAX_SIZE U(0x200000) + +#define PLAT_OCM_BASE U(0xBBF00000) +#define PLAT_OCM_LIMIT U(0xBC000000) + +#if defined(TRANSFER_LIST) +/* + * FIXME: This address should come from firmware before TF-A + * Having this to make sure the transfer list functionality works + */ +#define FW_HANDOFF_BASE U(0x70000000) +#define FW_HANDOFF_SIZE U(0x10000) +#endif + +#define IS_TFA_IN_OCM(x) ((x >= PLAT_OCM_BASE) && (x < PLAT_OCM_LIMIT)) + +#ifndef MAX_MMAP_REGIONS +#if (defined(XILINX_OF_BOARD_DTB_ADDR) && !IS_TFA_IN_OCM(BL31_BASE)) +#define MAX_MMAP_REGIONS 11 +#else +#define MAX_MMAP_REGIONS 10 +#endif +#endif + +#ifndef MAX_XLAT_TABLES +#define MAX_XLAT_TABLES U(12) +#endif + +#define CACHE_WRITEBACK_SHIFT U(6) +#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) + +#define PLAT_GICD_BASE_VALUE U(0xE2000000) +#define PLAT_GICR_BASE_VALUE U(0xE2060000) + +/* + * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 + * terminology. On a GICv2 system or mode, the lists will be merged and treated + * as Group 0 interrupts. + */ +#define PLAT_IPI_IRQ 89 +#define PLAT_VERSAL_IPI_IRQ PLAT_IPI_IRQ + +#define PLAT_G1S_IRQ_PROPS(grp) \ + INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \ + GIC_INTR_CFG_LEVEL) + +#define PLAT_G0_IRQ_PROPS(grp) \ + INTR_PROP_DESC(PLAT_VERSAL_IPI_IRQ, GIC_HIGHEST_SEC_PRIORITY, grp, \ + GIC_INTR_CFG_EDGE), \ + +#define IRQ_MAX 200U + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/amd/versal2/include/scmi.h b/plat/amd/versal2/include/scmi.h new file mode 100644 index 000000000..0ab8b34a7 --- /dev/null +++ b/plat/amd/versal2/include/scmi.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SCMI_H +#define SCMI_H + +#include "versal2-scmi.h" + +#define SIP_SCMI (0xC200ffffU) +#define SMT_BUFFER_BASE 0x7fffe000 + +void init_scmi_server(void); + +#define SCMI_VENDOR "AMD" +#define SCMI_PRODUCT "Versal Gen 2" + +#endif /* DEF_H */ diff --git a/plat/amd/versal2/include/versal2-scmi.h b/plat/amd/versal2/include/versal2-scmi.h new file mode 100644 index 000000000..4d581e498 --- /dev/null +++ b/plat/amd/versal2/include/versal2-scmi.h @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Macros IDs for AMD Versal Gen 2 + * + * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * Michal Simek + */ + +#ifndef _VERSAL2_SCMI_H +#define _VERSAL2_SCMI_H + +#define CLK_GEM0_0 0 +#define CLK_GEM0_1 1 +#define CLK_GEM0_2 2 +#define CLK_GEM0_3 3 +#define CLK_GEM0_4 4 +#define CLK_GEM1_0 5 +#define CLK_GEM1_1 6 +#define CLK_GEM1_2 7 +#define CLK_GEM1_3 8 +#define CLK_GEM1_4 9 +#define CLK_SERIAL0_0 10 +#define CLK_SERIAL0_1 11 +#define CLK_SERIAL1_0 12 +#define CLK_SERIAL1_1 13 +#define CLK_UFS0_0 14 +#define CLK_UFS0_1 15 +#define CLK_UFS0_2 16 +#define CLK_USB0_0 17 +#define CLK_USB0_1 18 +#define CLK_USB0_2 19 +#define CLK_USB1_0 20 +#define CLK_USB1_1 21 +#define CLK_USB1_2 22 +#define CLK_MMC0_0 23 +#define CLK_MMC0_1 24 +#define CLK_MMC0_2 25 +#define CLK_MMC1_0 26 +#define CLK_MMC1_1 27 +#define CLK_MMC1_2 28 +#define CLK_TTC0_0 29 +#define CLK_TTC1_0 30 +#define CLK_TTC2_0 31 +#define CLK_TTC3_0 32 +#define CLK_TTC4_0 33 +#define CLK_TTC5_0 34 +#define CLK_TTC6_0 35 +#define CLK_TTC7_0 36 +#define CLK_I2C0_0 37 +#define CLK_I2C1_0 38 +#define CLK_I2C2_0 39 +#define CLK_I2C3_0 40 +#define CLK_I2C4_0 41 +#define CLK_I2C5_0 42 +#define CLK_I2C6_0 43 +#define CLK_I2C7_0 44 +#define CLK_OSPI0_0 45 +#define CLK_QSPI0_0 46 +#define CLK_QSPI0_1 47 +#define CLK_WWDT0_0 48 +#define CLK_WWDT1_0 49 +#define CLK_WWDT2_0 50 +#define CLK_WWDT3_0 51 +#define CLK_ADMA0_0 52 +#define CLK_ADMA0_1 53 +#define CLK_ADMA1_0 54 +#define CLK_ADMA1_1 55 +#define CLK_ADMA2_0 56 +#define CLK_ADMA2_1 57 +#define CLK_ADMA3_0 58 +#define CLK_ADMA3_1 59 +#define CLK_ADMA4_0 60 +#define CLK_ADMA4_1 61 +#define CLK_ADMA5_0 62 +#define CLK_ADMA5_1 63 +#define CLK_ADMA6_0 64 +#define CLK_ADMA6_1 65 +#define CLK_ADMA7_0 66 +#define CLK_ADMA7_1 67 +#define CLK_CAN0_0 68 +#define CLK_CAN0_1 69 +#define CLK_CAN1_0 70 +#define CLK_CAN1_1 71 +#define CLK_CAN2_0 72 +#define CLK_CAN2_1 73 +#define CLK_CAN3_0 74 +#define CLK_CAN3_1 75 +#define CLK_PS_GPIO_0 76 +#define CLK_PMC_GPIO_0 77 +#define CLK_SPI0_0 78 +#define CLK_SPI0_1 79 +#define CLK_SPI1_0 80 +#define CLK_SPI1_1 81 +#define CLK_I3C0_0 82 +#define CLK_I3C1_0 83 +#define CLK_I3C2_0 84 +#define CLK_I3C3_0 85 +#define CLK_I3C4_0 86 +#define CLK_I3C5_0 87 +#define CLK_I3C6_0 88 +#define CLK_I3C7_0 89 + +#define RESET_GEM0_0 0 +#define RESET_GEM1_0 1 +#define RESET_SERIAL0_0 2 +#define RESET_SERIAL1_0 3 +#define RESET_UFS0_0 4 +#define RESET_I2C0_0 5 +#define RESET_I2C1_0 6 +#define RESET_I2C2_0 7 +#define RESET_I2C3_0 8 +#define RESET_I2C4_0 9 +#define RESET_I2C5_0 10 +#define RESET_I2C6_0 11 +#define RESET_I2C7_0 12 +#define RESET_I2C8_0 13 +#define RESET_OSPI0_0 14 +#define RESET_USB0_0 15 +#define RESET_USB0_1 16 +#define RESET_USB0_2 17 +#define RESET_USB1_0 18 +#define RESET_USB1_1 19 +#define RESET_USB1_2 20 +#define RESET_MMC0_0 21 +#define RESET_MMC1_0 22 +#define RESET_SPI0_0 23 +#define RESET_SPI1_0 24 +#define RESET_QSPI0_0 25 +#define RESET_I3C0_0 26 +#define RESET_I3C1_0 27 +#define RESET_I3C2_0 28 +#define RESET_I3C3_0 29 +#define RESET_I3C4_0 30 +#define RESET_I3C5_0 31 +#define RESET_I3C6_0 32 +#define RESET_I3C7_0 33 +#define RESET_I3C8_0 34 + +#endif /* _VERSAL2_SCMI_H */ diff --git a/plat/amd/versal2/plat_psci.c b/plat/amd/versal2/plat_psci.c new file mode 100644 index 000000000..4faa434ce --- /dev/null +++ b/plat/amd/versal2/plat_psci.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define PM_RET_ERROR_NOFEATURE U(19) +#define ALWAYSTRUE true + +static uintptr_t _sec_entry; + +static void zynqmp_cpu_standby(plat_local_state_t cpu_state) +{ + dsb(); + wfi(); +} + +#define MPIDR_MT_BIT (24) + +static int32_t zynqmp_nopmu_pwr_domain_on(u_register_t mpidr) +{ + uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr) & ~BIT(MPIDR_MT_BIT); + uint32_t cpu = cpu_id % PLATFORM_CORE_COUNT_PER_CLUSTER; + uint32_t cluster = cpu_id / PLATFORM_CORE_COUNT_PER_CLUSTER; + uintptr_t apu_cluster_base = 0, apu_pcli_base, apu_pcli_cluster = 0; + uintptr_t rst_apu_cluster = PSX_CRF + RST_APU0_OFFSET + ((uint64_t)cluster * 0x4U); + + VERBOSE("%s: mpidr: 0x%lx, cpuid: %x, cpu: %x, cluster: %x\n", + __func__, mpidr, cpu_id, cpu, cluster); + + if (cpu_id == -1) { + return PSCI_E_INTERN_FAIL; + } + + if (cluster > 3) { + panic(); + } + + apu_pcli_cluster = APU_PCLI + APU_PCLI_CLUSTER_OFFSET + ((uint64_t)cluster * APU_PCLI_CLUSTER_STEP); + apu_cluster_base = APU_CLUSTER0 + ((uint64_t)cluster * APU_CLUSTER_STEP); + + /* Enable clock */ + mmio_setbits_32(PSX_CRF + ACPU0_CLK_CTRL + ((uint64_t)cluster * 0x4U), ACPU_CLK_CTRL_CLKACT); + + /* Enable cluster states */ + mmio_setbits_32(apu_pcli_cluster + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_SET); + mmio_setbits_32(apu_pcli_cluster + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST); + + /* assert core reset */ + mmio_setbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu)); + + /* program RVBAR */ + mmio_write_32(apu_cluster_base + APU_RVBAR_L_0 + (cpu << 3), + (uint32_t)_sec_entry); + mmio_write_32(apu_cluster_base + APU_RVBAR_H_0 + (cpu << 3), + _sec_entry >> 32); + + /* de-assert core reset */ + mmio_clrbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu)); + + /* clear cluster resets */ + mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_WARM_RESET); + mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_COLD_RESET); + + apu_pcli_base = APU_PCLI + (APU_PCLI_CPU_STEP * cpu) + + (APU_PCLI_CLUSTER_CPU_STEP * cluster); + + mmio_write_32(apu_pcli_base + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_CLEAR); + mmio_write_32(apu_pcli_base + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST); + + return PSCI_E_SUCCESS; +} + +static void zynqmp_nopmu_pwr_domain_off(const psci_power_state_t *target_state) +{ + plat_gic_cpuif_disable(); +} + +static void __dead2 zynqmp_nopmu_system_reset(void) +{ + while (ALWAYSTRUE) { + wfi(); + } +} + +static int32_t zynqmp_validate_ns_entrypoint(uint64_t ns_entrypoint) +{ + VERBOSE("Validate ns_entry point %lx\n", ns_entrypoint); + + if ((ns_entrypoint) != 0U) { + return PSCI_E_SUCCESS; + } else { + return PSCI_E_INVALID_ADDRESS; + } +} + +static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + plat_gic_pcpu_init(); + plat_gic_cpuif_enable(); +} + +static void __dead2 zynqmp_system_off(void) +{ + while (ALWAYSTRUE) { + wfi(); + } +} + +static int32_t zynqmp_validate_power_state(uint32_t power_state, psci_power_state_t *req_state) +{ + return PSCI_E_SUCCESS; +} + +static const struct plat_psci_ops _nopmc_psci_ops = { + .cpu_standby = zynqmp_cpu_standby, + .pwr_domain_on = zynqmp_nopmu_pwr_domain_on, + .pwr_domain_off = zynqmp_nopmu_pwr_domain_off, + .system_reset = zynqmp_nopmu_system_reset, + .validate_ns_entrypoint = zynqmp_validate_ns_entrypoint, + .pwr_domain_on_finish = zynqmp_pwr_domain_on_finish, + .system_off = zynqmp_system_off, + .validate_power_state = zynqmp_validate_power_state, +}; + +/******************************************************************************* + * Export the platform specific power ops. + ******************************************************************************/ +int32_t plat_setup_psci_ops(uintptr_t sec_entrypoint, + const struct plat_psci_ops **psci_ops) +{ + _sec_entry = sec_entrypoint; + + VERBOSE("Setting up entry point %lx\n", _sec_entry); + + *psci_ops = &_nopmc_psci_ops; + + return 0; +} + +int sip_svc_setup_init(void) +{ + return 0; +} + +static int32_t no_pm_ioctl(uint32_t device_id, uint32_t ioctl_id, + uint32_t arg1, uint32_t arg2) +{ + VERBOSE("%s: ioctl_id: %x, arg1: %x\n", __func__, ioctl_id, arg1); + if (ioctl_id == IOCTL_OSPI_MUX_SELECT) { + mmio_write_32(SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL, arg1); + return 0; + } + return PM_RET_ERROR_NOFEATURE; +} + +static uint64_t no_pm_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, + uint64_t x4, void *cookie, void *handle, uint64_t flags) +{ + int32_t ret; + uint32_t arg[4], api_id; + + arg[0] = (uint32_t)x1; + arg[1] = (uint32_t)(x1 >> 32); + arg[2] = (uint32_t)x2; + arg[3] = (uint32_t)(x2 >> 32); + + api_id = smc_fid & FUNCID_NUM_MASK; + VERBOSE("%s: smc_fid: %x, api_id=0x%x\n", __func__, smc_fid, api_id); + + switch (api_id) { + case PM_IOCTL: + { + ret = no_pm_ioctl(arg[0], arg[1], arg[2], arg[3]); + SMC_RET1(handle, (uint64_t)ret); + } + case PM_GET_CHIPID: + { + uint32_t idcode, version; + + idcode = mmio_read_32(PMC_TAP); + version = mmio_read_32(PMC_TAP_VERSION); + SMC_RET2(handle, ((uint64_t)idcode << 32), version); + } + default: + WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} + +uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, + void *cookie, void *handle, uint64_t flags) +{ + return no_pm_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); +} diff --git a/plat/amd/versal2/plat_topology.c b/plat/amd/versal2/plat_topology.c new file mode 100644 index 000000000..076313981 --- /dev/null +++ b/plat/amd/versal2/plat_topology.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include + +static const uint8_t plat_power_domain_tree_desc[] = { + /* Number of root nodes */ + 1, + /* Number of clusters */ + PLATFORM_CLUSTER_COUNT, + /* Number of children for the first cluster node */ + PLATFORM_CORE_COUNT_PER_CLUSTER, + /* Number of children for the second cluster node */ + PLATFORM_CORE_COUNT_PER_CLUSTER, + /* Number of children for the third cluster node */ + PLATFORM_CORE_COUNT_PER_CLUSTER, + /* Number of children for the fourth cluster node */ + PLATFORM_CORE_COUNT_PER_CLUSTER, +}; + +const uint8_t *plat_get_power_domain_tree_desc(void) +{ + return plat_power_domain_tree_desc; +} + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error code (-1) is returned + * in case the MPIDR is invalid. + ******************************************************************************/ +int32_t plat_core_pos_by_mpidr(u_register_t mpidr) +{ + uint32_t cluster_id, cpu_id; + + mpidr &= MPIDR_AFFINITY_MASK; + + cluster_id = MPIDR_AFFLVL2_VAL(mpidr); + cpu_id = MPIDR_AFFLVL1_VAL(mpidr); + + if (cluster_id >= PLATFORM_CLUSTER_COUNT) { + return -3; + } + + /* + * Validate cpu_id by checking whether it represents a CPU in + * one of the two clusters present on the platform. + */ + if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER) { + return -1; + } + + return (cpu_id + (cluster_id * PLATFORM_CORE_COUNT_PER_CLUSTER)); +} diff --git a/plat/amd/versal2/platform.mk b/plat/amd/versal2/platform.mk new file mode 100644 index 000000000..c07fc36a8 --- /dev/null +++ b/plat/amd/versal2/platform.mk @@ -0,0 +1,127 @@ +# Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved. +# Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved. +# Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +PLAT_PATH := plat/amd/versal2 + +# A78 Erratum for SoC +ERRATA_A78_AE_1941500 := 1 +ERRATA_A78_AE_1951502 := 1 +ERRATA_A78_AE_2376748 := 1 +ERRATA_A78_AE_2395408 := 1 +ERRATA_ABI_SUPPORT := 1 + +# Platform Supports Armv8.2 extensions +ARM_ARCH_MAJOR := 8 +ARM_ARCH_MINOR := 2 + +override PROGRAMMABLE_RESET_ADDRESS := 1 +PSCI_EXTENDED_STATE_ID := 1 +SEPARATE_CODE_AND_RODATA := 1 +override RESET_TO_BL31 := 1 +PL011_GENERIC_UART := 1 +IPI_CRC_CHECK := 0 +GIC_ENABLE_V4_EXTN := 0 +GICV3_SUPPORT_GIC600 := 1 + +override CTX_INCLUDE_AARCH32_REGS := 0 + +ifdef MEM_BASE + $(eval $(call add_define,MEM_BASE)) + + ifndef MEM_SIZE + $(error "ATF_BASE defined without ATF_SIZE") + endif + $(eval $(call add_define,MEM_SIZE)) + + ifdef MEM_PROGBITS_SIZE + $(eval $(call add_define,MEM_PROGBITS_SIZE)) + endif +endif + +ifdef BL32_MEM_BASE + $(eval $(call add_define,BL32_MEM_BASE)) + + ifndef BL32_MEM_SIZE + $(error "BL32_BASE defined without BL32_SIZE") + endif + $(eval $(call add_define,BL32_MEM_SIZE)) +endif + +ifdef IPI_CRC_CHECK + $(eval $(call add_define,IPI_CRC_CHECK)) +endif + +USE_COHERENT_MEM := 0 +HW_ASSISTED_COHERENCY := 1 + +CONSOLE ?= pl011 +ifeq (${CONSOLE}, $(filter ${CONSOLE},pl011 pl011_0 pl011_1 dcc)) +else + $(error Please define CONSOLE) +endif + +$(eval $(call add_define_val,CONSOLE,CONSOLE_ID_${CONSOLE})) + +ifdef XILINX_OF_BOARD_DTB_ADDR +$(eval $(call add_define,XILINX_OF_BOARD_DTB_ADDR)) +endif + +PLAT_INCLUDES := -Iinclude/plat/arm/common/ \ + -Iplat/xilinx/common/include/ \ + -Iplat/xilinx/common/ipi_mailbox_service/ \ + -I${PLAT_PATH}/include/ \ + -Iplat/xilinx/versal/pm_service/ + +# Include GICv3 driver files +include drivers/arm/gic/v3/gicv3.mk +include lib/xlat_tables_v2/xlat_tables.mk +include lib/libfdt/libfdt.mk + +PLAT_BL_COMMON_SOURCES := \ + drivers/arm/dcc/dcc_console.c \ + drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ + ${GICV3_SOURCES} \ + drivers/arm/pl011/aarch64/pl011_console.S \ + plat/common/aarch64/crash_console_helpers.S \ + plat/arm/common/arm_common.c \ + plat/common/plat_gicv3.c \ + ${PLAT_PATH}/aarch64/helpers.S \ + ${PLAT_PATH}/aarch64/common.c \ + ${PLAT_PATH}/plat_topology.c \ + ${XLAT_TABLES_LIB_SRCS} + +BL31_SOURCES += drivers/arm/cci/cci.c \ + lib/cpus/aarch64/cortex_a78_ae.S \ + lib/cpus/aarch64/cortex_a78.S \ + plat/common/plat_psci_common.c \ + drivers/scmi-msg/base.c \ + drivers/scmi-msg/entry.c \ + drivers/scmi-msg/smt.c \ + drivers/scmi-msg/clock.c \ + drivers/scmi-msg/power_domain.c \ + drivers/scmi-msg/reset_domain.c \ + ${PLAT_PATH}/scmi.c + +BL31_SOURCES += ${PLAT_PATH}/plat_psci.c + +BL31_SOURCES += plat/xilinx/common/plat_fdt.c \ + plat/xilinx/common/plat_startup.c \ + plat/xilinx/common/ipi.c \ + plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \ + ${PLAT_PATH}/soc_ipi.c \ + plat/xilinx/common/versal.c \ + ${PLAT_PATH}/bl31_setup.c \ + common/fdt_fixup.c \ + ${LIBFDT_SRCS} \ + ${PLAT_PATH}/sip_svc_setup.c \ + ${PLAT_PATH}/gicv3.c + +ifeq (${ERRATA_ABI_SUPPORT}, 1) +# enable the cpu macros for errata abi interface +CORTEX_A78_AE_H_INC := 1 +$(eval $(call add_define, CORTEX_A78_AE_H_INC)) +endif diff --git a/plat/amd/versal2/scmi.c b/plat/amd/versal2/scmi.c new file mode 100644 index 000000000..c3c517a9c --- /dev/null +++ b/plat/amd/versal2/scmi.c @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "plat_private.h" + +#define HIGH (1) +#define LOW (0) + +struct scmi_clk { + unsigned long clock_id; + unsigned long rate; + const char *name; + bool enabled; +}; + +#define CLOCK_CELL(_scmi_id, _id, _name, _init_enabled, _rate) \ + [_scmi_id] = { \ + .clock_id = (_id), \ + .name = (_name), \ + .enabled = (_init_enabled), \ + .rate = (_rate), \ + } + +static struct scmi_clk scmi0_clock[] = { + CLOCK_CELL(CLK_GEM0_0, CLK_GEM0_0, "gem0_pclk", true, 100000000), + CLOCK_CELL(CLK_GEM0_1, CLK_GEM0_1, "gem0_hclk", true, 100000000), + CLOCK_CELL(CLK_GEM0_2, CLK_GEM0_2, "gem0_tx_clk", true, 125000000), + CLOCK_CELL(CLK_GEM0_3, CLK_GEM0_3, "gem0_rx_clk", true, 100000000), + CLOCK_CELL(CLK_GEM0_4, CLK_GEM0_4, "gem0_tsu_clk", true, 100000000), + CLOCK_CELL(CLK_GEM1_0, CLK_GEM1_0, "gem1_pclk", true, 100000000), + CLOCK_CELL(CLK_GEM1_1, CLK_GEM1_1, "gem1_hclk", true, 100000000), + CLOCK_CELL(CLK_GEM1_2, CLK_GEM1_2, "gem1_tx_clk", true, 125000000), + CLOCK_CELL(CLK_GEM1_3, CLK_GEM1_3, "gem1_rx_clk", true, 100000000), + CLOCK_CELL(CLK_GEM1_4, CLK_GEM1_4, "gem1_tsu_clk", true, 100000000), + CLOCK_CELL(CLK_SERIAL0_0, CLK_SERIAL0_0, "uart0_uartclk", true, 100000000), + CLOCK_CELL(CLK_SERIAL0_1, CLK_SERIAL0_1, "uart0_apb_pclk", true, 100000000), + CLOCK_CELL(CLK_SERIAL1_0, CLK_SERIAL1_0, "uart1_uartclk", true, 100000000), + CLOCK_CELL(CLK_SERIAL1_1, CLK_SERIAL1_1, "uart1_apb_pclk", true, 100000000), + CLOCK_CELL(CLK_UFS0_0, CLK_UFS0_0, "ufs_core_clk", true, 100000000), + CLOCK_CELL(CLK_UFS0_1, CLK_UFS0_1, "ufs_phy_clk", true, 100000000), + CLOCK_CELL(CLK_UFS0_2, CLK_UFS0_2, "ufs_ref_pclk", true, 100000000), + CLOCK_CELL(CLK_USB0_0, CLK_USB0_0, "usb0_bus_clk", true, 100000000), + CLOCK_CELL(CLK_USB0_1, CLK_USB0_1, "usb0_ref_clk", true, 100000000), + CLOCK_CELL(CLK_USB0_2, CLK_USB0_2, "usb0_dwc_clk", true, 100000000), + CLOCK_CELL(CLK_USB1_0, CLK_USB1_0, "usb1_bus_clk", true, 100000000), + CLOCK_CELL(CLK_USB1_1, CLK_USB1_1, "usb1_ref_clk", true, 100000000), + CLOCK_CELL(CLK_USB1_2, CLK_USB1_2, "usb1_dwc_clk", true, 100000000), + CLOCK_CELL(CLK_MMC0_0, CLK_MMC0_0, "mmc0_xin_clk", true, 100000000), + CLOCK_CELL(CLK_MMC0_1, CLK_MMC0_1, "mmc0_ahb_clk", true, 100000000), + CLOCK_CELL(CLK_MMC0_2, CLK_MMC0_2, "mmc0_gate_clk", true, 100000000), + CLOCK_CELL(CLK_MMC1_0, CLK_MMC1_0, "mmc1_xin_clk", true, 100000000), + CLOCK_CELL(CLK_MMC1_1, CLK_MMC1_1, "mmc1_ahb_clk", true, 100000000), + CLOCK_CELL(CLK_MMC1_2, CLK_MMC1_2, "mmc1_gate_clk", true, 100000000), + CLOCK_CELL(CLK_TTC0_0, CLK_TTC0_0, "ttc0_clk", true, 100000000), + CLOCK_CELL(CLK_TTC1_0, CLK_TTC1_0, "ttc1_clk", true, 100000000), + CLOCK_CELL(CLK_TTC2_0, CLK_TTC2_0, "ttc2_clk", true, 100000000), + CLOCK_CELL(CLK_TTC3_0, CLK_TTC3_0, "ttc3_clk", true, 100000000), + CLOCK_CELL(CLK_TTC4_0, CLK_TTC4_0, "ttc4_clk", true, 100000000), + CLOCK_CELL(CLK_TTC5_0, CLK_TTC5_0, "ttc5_clk", true, 100000000), + CLOCK_CELL(CLK_TTC6_0, CLK_TTC6_0, "ttc6_clk", true, 100000000), + CLOCK_CELL(CLK_TTC7_0, CLK_TTC7_0, "ttc7_clk", true, 100000000), + CLOCK_CELL(CLK_I2C0_0, CLK_I2C0_0, "i2c0_clk", true, 100000000), + CLOCK_CELL(CLK_I2C1_0, CLK_I2C1_0, "i2c1_clk", true, 100000000), + CLOCK_CELL(CLK_I2C2_0, CLK_I2C2_0, "i2c2_clk", true, 100000000), + CLOCK_CELL(CLK_I2C3_0, CLK_I2C3_0, "i2c3_clk", true, 100000000), + CLOCK_CELL(CLK_I2C4_0, CLK_I2C4_0, "i2c4_clk", true, 100000000), + CLOCK_CELL(CLK_I2C5_0, CLK_I2C5_0, "i2c5_clk", true, 100000000), + CLOCK_CELL(CLK_I2C6_0, CLK_I2C6_0, "i2c6_clk", true, 100000000), + CLOCK_CELL(CLK_I2C7_0, CLK_I2C7_0, "i2c7_clk", true, 100000000), + CLOCK_CELL(CLK_OSPI0_0, CLK_OSPI0_0, "ospi0_clk", true, 100000000), + CLOCK_CELL(CLK_QSPI0_0, CLK_QSPI0_0, "qpsi0_ref_clk", true, 100000000), + CLOCK_CELL(CLK_QSPI0_1, CLK_QSPI0_1, "qspi0_pclk", true, 100000000), + CLOCK_CELL(CLK_WWDT0_0, CLK_WWDT0_0, "wwdt0_clk", true, 100000000), + CLOCK_CELL(CLK_WWDT1_0, CLK_WWDT1_0, "wwdt1_clk", true, 100000000), + CLOCK_CELL(CLK_WWDT2_0, CLK_WWDT2_0, "wwdt2_clk", true, 100000000), + CLOCK_CELL(CLK_WWDT3_0, CLK_WWDT3_0, "wwdt3_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA0_0, CLK_ADMA0_0, "adma0_main_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA0_1, CLK_ADMA0_1, "adma0_apb_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA1_0, CLK_ADMA1_0, "adma1_main_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA1_1, CLK_ADMA1_1, "adma1_apb_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA2_0, CLK_ADMA2_0, "adma2_main_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA2_1, CLK_ADMA2_1, "adma2_apb_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA3_0, CLK_ADMA3_0, "adma3_main_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA3_1, CLK_ADMA3_1, "adma3_apb_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA4_0, CLK_ADMA4_0, "adma4_main_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA4_1, CLK_ADMA4_1, "adma4_apb_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA5_0, CLK_ADMA5_0, "adma5_main_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA5_1, CLK_ADMA5_1, "adma5_apb_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA6_0, CLK_ADMA6_0, "adma6_main_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA6_1, CLK_ADMA6_1, "adma6_apb_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA7_0, CLK_ADMA7_0, "adma7_main_clk", true, 100000000), + CLOCK_CELL(CLK_ADMA7_1, CLK_ADMA7_1, "adma7_apb_clk", true, 100000000), + CLOCK_CELL(CLK_CAN0_0, CLK_CAN0_0, "can0_can_clk", true, 100000000), + CLOCK_CELL(CLK_CAN0_1, CLK_CAN0_1, "can0_axi_clk", true, 100000000), + CLOCK_CELL(CLK_CAN1_0, CLK_CAN1_0, "can1_can_clk", true, 100000000), + CLOCK_CELL(CLK_CAN1_1, CLK_CAN1_1, "can1_axi_clk", true, 100000000), + CLOCK_CELL(CLK_CAN2_0, CLK_CAN2_0, "can2_can_clk", true, 100000000), + CLOCK_CELL(CLK_CAN2_1, CLK_CAN2_1, "can2_axi_clk", true, 100000000), + CLOCK_CELL(CLK_CAN3_0, CLK_CAN3_0, "can3_can_clk", true, 100000000), + CLOCK_CELL(CLK_CAN3_1, CLK_CAN3_1, "can3_axi_clk", true, 100000000), + CLOCK_CELL(CLK_PS_GPIO_0, CLK_PS_GPIO_0, "ps_gpio_clk", true, 100000000), + CLOCK_CELL(CLK_PMC_GPIO_0, CLK_PMC_GPIO_0, "pmc_gpio_clk", true, 100000000), + CLOCK_CELL(CLK_SPI0_0, CLK_SPI0_0, "spi0_ref_clk", true, 100000000), + CLOCK_CELL(CLK_SPI0_1, CLK_SPI0_1, "spi0_pclk", true, 100000000), + CLOCK_CELL(CLK_SPI1_0, CLK_SPI1_0, "spi1_ref_clk", true, 100000000), + CLOCK_CELL(CLK_SPI1_1, CLK_SPI1_1, "spi1_pclk", true, 100000000), + CLOCK_CELL(CLK_I3C0_0, CLK_I3C0_0, "i3c0_clk", true, 100000000), + CLOCK_CELL(CLK_I3C1_0, CLK_I3C1_0, "i3c1_clk", true, 100000000), + CLOCK_CELL(CLK_I3C2_0, CLK_I3C2_0, "i3c2_clk", true, 100000000), + CLOCK_CELL(CLK_I3C3_0, CLK_I3C3_0, "i3c3_clk", true, 100000000), + CLOCK_CELL(CLK_I3C4_0, CLK_I3C4_0, "i3c4_clk", true, 100000000), + CLOCK_CELL(CLK_I3C5_0, CLK_I3C5_0, "i3c5_clk", true, 100000000), + CLOCK_CELL(CLK_I3C6_0, CLK_I3C6_0, "i3c6_clk", true, 100000000), + CLOCK_CELL(CLK_I3C7_0, CLK_I3C7_0, "i3c7_clk", true, 100000000), +}; + +/* + * struct scmi_reset - Data for the exposed reset controller + * @reset_id: Reset identifier in RCC reset driver + * @name: Reset string ID exposed to agent + */ +struct scmi_reset { + unsigned long reset_id; + const char *name; +}; + +#define RESET_CELL(_scmi_id, _id, _name) \ + [_scmi_id] = { \ + .reset_id = (_id), \ + .name = (_name), \ + } + +static struct scmi_reset scmi0_reset[] = { + RESET_CELL(RESET_GEM0_0, RESET_GEM0_0, "gem0"), + RESET_CELL(RESET_GEM1_0, RESET_GEM1_0, "gem1"), + RESET_CELL(RESET_SERIAL0_0, RESET_SERIAL0_0, "serial0"), + RESET_CELL(RESET_SERIAL1_0, RESET_SERIAL1_0, "serial1"), + RESET_CELL(RESET_UFS0_0, RESET_UFS0_0, "ufs0"), + RESET_CELL(RESET_I2C0_0, RESET_I2C0_0, "i2c0"), + RESET_CELL(RESET_I2C1_0, RESET_I2C1_0, "i2c1"), + RESET_CELL(RESET_I2C2_0, RESET_I2C2_0, "i2c2"), + RESET_CELL(RESET_I2C3_0, RESET_I2C3_0, "i2c3"), + RESET_CELL(RESET_I2C4_0, RESET_I2C4_0, "i2c4"), + RESET_CELL(RESET_I2C5_0, RESET_I2C5_0, "i2c5"), + RESET_CELL(RESET_I2C6_0, RESET_I2C6_0, "i2c6"), + RESET_CELL(RESET_I2C7_0, RESET_I2C7_0, "i2c7"), + RESET_CELL(RESET_I2C8_0, RESET_I2C8_0, "i2c8"), + RESET_CELL(RESET_OSPI0_0, RESET_OSPI0_0, "ospi"), + RESET_CELL(RESET_USB0_0, RESET_USB0_0, "usb0_0"), + RESET_CELL(RESET_USB0_1, RESET_USB0_1, "usb0_1"), + RESET_CELL(RESET_USB0_2, RESET_USB0_2, "usb0_2"), + RESET_CELL(RESET_USB1_0, RESET_USB1_0, "usb1_0"), + RESET_CELL(RESET_USB1_1, RESET_USB1_1, "usb1_1"), + RESET_CELL(RESET_USB1_2, RESET_USB1_2, "usb1_2"), + RESET_CELL(RESET_MMC0_0, RESET_MMC0_0, "mmc0"), + RESET_CELL(RESET_MMC1_0, RESET_MMC1_0, "mmc1"), + RESET_CELL(RESET_SPI0_0, RESET_SPI0_0, "spi0"), + RESET_CELL(RESET_SPI1_0, RESET_SPI1_0, "spi1"), + RESET_CELL(RESET_QSPI0_0, RESET_QSPI0_0, "qspi"), + RESET_CELL(RESET_I3C0_0, RESET_I3C0_0, "i3c0"), + RESET_CELL(RESET_I3C1_0, RESET_I3C1_0, "i3c1"), + RESET_CELL(RESET_I3C2_0, RESET_I3C2_0, "i3c2"), + RESET_CELL(RESET_I3C3_0, RESET_I3C3_0, "i3c3"), + RESET_CELL(RESET_I3C4_0, RESET_I3C4_0, "i3c4"), + RESET_CELL(RESET_I3C5_0, RESET_I3C5_0, "i3c5"), + RESET_CELL(RESET_I3C6_0, RESET_I3C6_0, "i3c6"), + RESET_CELL(RESET_I3C7_0, RESET_I3C7_0, "i3c7"), + RESET_CELL(RESET_I3C8_0, RESET_I3C8_0, "i3c8"), +}; + +struct scmi_resources { + struct scmi_clk *clock; + size_t clock_count; + struct scmi_reset *reset; + size_t reset_count; + +}; + +static const struct scmi_resources resources[] = { + [0] = { + .clock = scmi0_clock, + .clock_count = ARRAY_SIZE(scmi0_clock), + .reset = scmi0_reset, + .reset_count = ARRAY_SIZE(scmi0_reset), + }, +}; + +static const struct scmi_resources *find_resource(unsigned int agent_id) +{ + assert(agent_id < ARRAY_SIZE(resources)); + + return &resources[agent_id]; +} + +static struct scmi_clk *clk_find(unsigned int agent_id, unsigned int scmi_id) +{ + const struct scmi_resources *resource = find_resource(agent_id); + size_t n = 0U; + struct scmi_clk *ret = NULL; + + if (resource != NULL) { + for (n = 0U; n < resource->clock_count; n++) { + if (n == scmi_id) { + ret = &resource->clock[n]; + break; + } + } + } + + return ret; +} + +size_t plat_scmi_clock_count(unsigned int agent_id) +{ + const struct scmi_resources *resource = find_resource(agent_id); + size_t ret; + + if (resource == NULL) { + ret = 0U; + } else { + VERBOSE("SCMI: CLK: %d clocks\n", (unsigned int)resource->clock_count); + + ret = resource->clock_count; + } + return ret; +} + +const char *plat_scmi_clock_get_name(unsigned int agent_id, unsigned int scmi_id) +{ + struct scmi_clk *clock = clk_find(agent_id, scmi_id); + const char *ret; + + if (clock == NULL) { + ret = NULL; + } else { + VERBOSE("SCMI: CLK: id: %d, get_name: %s\n", scmi_id, clock->name); + + ret = clock->name; + } + return ret; +}; + +/* Called by Linux */ +int32_t plat_scmi_clock_rates_array(unsigned int agent_id, unsigned int scmi_id, + unsigned long *array, size_t *nb_elts, + uint32_t start_idx) +{ + struct scmi_clk *clock = clk_find(agent_id, scmi_id); + + if (clock == NULL) { + return SCMI_NOT_FOUND; + } + + if (start_idx > 0) { + return SCMI_OUT_OF_RANGE; + } + + if (array == NULL) { + *nb_elts = 1U; + } else if (*nb_elts == 1U) { + *array = clock->rate; + VERBOSE("SCMI: CLK: id: %d, clk_name: %s, get_rate %lu\n", + scmi_id, clock->name, *array); + } else { + return SCMI_GENERIC_ERROR; + } + + return SCMI_SUCCESS; +} + +unsigned long plat_scmi_clock_get_rate(unsigned int agent_id, unsigned int scmi_id) +{ + struct scmi_clk *clock = clk_find(agent_id, scmi_id); + unsigned long ret; + + if ((clock == NULL)) { + ret = SCMI_NOT_FOUND; + } else { + VERBOSE("SCMI: CLK: id: %d, get_rate: %lu\n", scmi_id, clock->rate); + ret = clock->rate; + } + return ret; +} + +int32_t plat_scmi_clock_set_rate(unsigned int agent_id, unsigned int scmi_id, + unsigned long rate) +{ + struct scmi_clk *clock = clk_find(agent_id, scmi_id); + unsigned long ret = UL(SCMI_SUCCESS); + + if ((clock == NULL)) { + ret = SCMI_NOT_FOUND; + } else { + VERBOSE("SCMI: CLK: id: %d, set_rate: %lu\n", scmi_id, rate); + clock->rate = rate; + } + return ret; +} + +int32_t plat_scmi_clock_get_state(unsigned int agent_id, unsigned int scmi_id) +{ + struct scmi_clk *clock = clk_find(agent_id, scmi_id); + int32_t ret; + + if ((clock == NULL)) { + ret = SCMI_NOT_FOUND; + } else { + VERBOSE("SCMI: CLK: id: %d, get_state: %d\n", scmi_id, clock->enabled); + + if (clock->enabled) { + ret = HIGH; + } else { + ret = LOW; + } + } + return ret; +} + +int32_t plat_scmi_clock_set_state(unsigned int agent_id, unsigned int scmi_id, + bool enable_not_disable) +{ + struct scmi_clk *clock = clk_find(agent_id, scmi_id); + int32_t ret; + + if (clock == NULL) { + ret = SCMI_NOT_FOUND; + } else { + if (enable_not_disable) { + if (!clock->enabled) { + VERBOSE("SCMI: clock: %u enable\n", scmi_id); + clock->enabled = true; + } + } else { + if (clock->enabled) { + VERBOSE("SCMI: clock: %u disable\n", scmi_id); + clock->enabled = false; + } + } + + VERBOSE("SCMI: CLK: id: %d, set_state: %d\n", scmi_id, clock->enabled); + + ret = SCMI_SUCCESS; + } + + return ret; +} + + +/* + * Platform SCMI reset domains + */ +static struct scmi_reset *find_reset(unsigned int agent_id, + unsigned int scmi_id) +{ + const struct scmi_resources *resource = find_resource(agent_id); + size_t n; + + if (resource != NULL) { + for (n = 0U; n < resource->reset_count; n++) { + if (n == scmi_id) { + return &resource->reset[n]; + } + } + } + + return NULL; +} + +const char *plat_scmi_rstd_get_name(unsigned int agent_id, unsigned int scmi_id) +{ + const struct scmi_reset *reset = find_reset(agent_id, scmi_id); + + if (reset == NULL) { + return NULL; + } + + return reset->name; +} + +size_t plat_scmi_rstd_count(unsigned int agent_id) +{ + const struct scmi_resources *resource = find_resource(agent_id); + + if (resource == NULL) { + return 0U; + } + + return resource->reset_count; +} + +int32_t plat_scmi_rstd_autonomous(unsigned int agent_id, unsigned int scmi_id, + uint32_t state) +{ + const struct scmi_reset *reset = find_reset(agent_id, scmi_id); + + if (reset == NULL) { + return SCMI_NOT_FOUND; + } + + /* Supports only reset with context loss */ + if (state != 0U) { + return SCMI_NOT_SUPPORTED; + } + + NOTICE("SCMI reset on ID %lu/%s\n", + reset->reset_id, plat_scmi_rstd_get_name(agent_id, scmi_id)); + + return SCMI_SUCCESS; +} + +int32_t plat_scmi_rstd_set_state(unsigned int agent_id, unsigned int scmi_id, + bool assert_not_deassert) +{ + const struct scmi_reset *reset = find_reset(agent_id, scmi_id); + + if (reset == NULL) { + return SCMI_NOT_FOUND; + } + + if (assert_not_deassert) { + NOTICE("SCMI reset %lu/%s set\n", + reset->reset_id, plat_scmi_rstd_get_name(agent_id, scmi_id)); + } else { + NOTICE("SCMI reset %lu/%s release\n", + reset->reset_id, plat_scmi_rstd_get_name(agent_id, scmi_id)); + } + + return SCMI_SUCCESS; +} + +/* Currently only one channel is supported. Expectation is that channel 0 is used by NS SW */ +static struct scmi_msg_channel scmi_channel[] = { + [0] = { + .shm_addr = SMT_BUFFER_BASE, + .shm_size = SMT_BUF_SLOT_SIZE, + }, +}; + +struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id) +{ + assert(agent_id < ARRAY_SIZE(scmi_channel)); + + VERBOSE("%d: SCMI asking for channel\n", agent_id); + + /* Just in case that code is reused */ + return &scmi_channel[agent_id]; +} + +/* Base protocol implementations */ +const char *plat_scmi_vendor_name(void) +{ + return SCMI_VENDOR; +} + +const char *plat_scmi_sub_vendor_name(void) +{ + return SCMI_PRODUCT; +} + +/* Currently supporting Clocks and Reset Domains */ +static const uint8_t plat_protocol_list[] = { + SCMI_PROTOCOL_ID_BASE, + SCMI_PROTOCOL_ID_CLOCK, + SCMI_PROTOCOL_ID_RESET_DOMAIN, + /* + *SCMI_PROTOCOL_ID_POWER_DOMAIN, + *SCMI_PROTOCOL_ID_SENSOR, + */ + 0U /* Null termination */ +}; + +size_t plat_scmi_protocol_count(void) +{ + const size_t count = ARRAY_SIZE(plat_protocol_list) - 1U; + + VERBOSE("SCMI: Protocol count: %d\n", (int32_t)count); + + return count; +} + +const uint8_t *plat_scmi_protocol_list(unsigned int agent_id __unused) +{ + return plat_protocol_list; +} + +void init_scmi_server(void) +{ + size_t i; + int32_t ret; + + for (i = 0U; i < ARRAY_SIZE(scmi_channel); i++) + scmi_smt_init_agent_channel(&scmi_channel[i]); + + INFO("SCMI: Server initialized\n"); + + if (platform_id == QEMU) { + /* default setting is for QEMU */ + } else if (platform_id == SPP) { + for (i = 0U; i < ARRAY_SIZE(scmi0_clock); i++) { + + /* Keep i2c on 100MHz to calculate rates properly */ + if (i >= CLK_I2C0_0 && i <= CLK_I2C7_0) + continue; + /* + * SPP supports multiple versions. + * The cpu_clock value is set to corresponding SPP + * version in early platform setup, resuse the same + * value here. + */ + ret = plat_scmi_clock_set_rate(0, i, cpu_clock); + if (ret < 0) { + NOTICE("Failed to set clock rate for SPP scmi_id=%ld\n", i); + } + } + } else { + /* Making MISRA C 2012 15.7 compliant */ + } +} diff --git a/plat/amd/versal2/sip_svc_setup.c b/plat/amd/versal2/sip_svc_setup.c new file mode 100644 index 000000000..68500306c --- /dev/null +++ b/plat/amd/versal2/sip_svc_setup.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "ipi_mailbox_svc.h" +#include "plat_private.h" +#include "pm_svc_main.h" + +/* SMC function IDs for SiP Service queries */ +#define SIP_SVC_UID (0x8200ff01U) +#define SIP_SVC_VERSION (0x8200ff03U) + +/* SiP Service Calls version numbers */ +#define SIP_SVC_VERSION_MAJOR (0U) +#define SIP_SVC_VERSION_MINOR (1U) + +/* These macros are used to identify PM calls from the SMC function ID */ +#define SIP_FID_MASK GENMASK(23, 16) +#define XLNX_FID_MASK GENMASK(23, 12) +#define PM_FID_VALUE 0u +#define IPI_FID_VALUE 0x1000u +#define is_pm_fid(_fid) (((_fid) & XLNX_FID_MASK) == PM_FID_VALUE) +#define is_ipi_fid(_fid) (((_fid) & XLNX_FID_MASK) == IPI_FID_VALUE) + +/* SiP Service UUID */ +DEFINE_SVC_UUID2(_sip_uuid, + 0x0499eb70, 0x5ed0, 0x11ee, 0xb3, 0x0a, + 0x87, 0xd1, 0x1d, 0x4f, 0x8a, 0x9b); + +/** + * sip_svc_setup() - Setup SiP Service + * + * Return: 0 on success, negative error code on failure. + * + */ +static int32_t sip_svc_setup(void) +{ + return sip_svc_setup_init(); +} + +/* + * sip_svc_smc_handler() - Top-level SiP Service SMC handler + * + * Handler for all SiP SMC calls. Handles standard SIP requests + * and calls PM SMC handler if the call is for a PM-API function. + */ +static uintptr_t sip_svc_smc_handler(uint32_t smc_fid, + u_register_t x1, + u_register_t x2, + u_register_t x3, + u_register_t x4, + void *cookie, + void *handle, + u_register_t flags) +{ + VERBOSE("SMCID: 0x%08x, x1: 0x%016" PRIx64 ", x2: 0x%016" PRIx64 ", x3: 0x%016" PRIx64 ", x4: 0x%016" PRIx64 "\n", + smc_fid, x1, x2, x3, x4); + + if ((smc_fid & SIP_FID_MASK) != 0) { + WARN("SMC out of SiP assinged range: 0x%x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } + + /* Let PM SMC handler deal with PM-related requests */ + if (is_pm_fid(smc_fid)) { + return smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); + } + + /* Let IPI SMC handler deal with IPI-related requests if platform */ + if (is_ipi_fid(smc_fid)) { + return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); + } + + /* Let PM SMC handler deal with PM-related requests */ + switch (smc_fid) { + case SIP_SVC_UID: + SMC_UUID_RET(handle, _sip_uuid); + + case SIP_SVC_VERSION: + SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR); + + case SIP_SCMI: + if (platform_id != EMU) { + scmi_smt_fastcall_smc_entry(0); + SMC_RET1(handle, 0); + } + WARN("SCMI is not working on EMU\n"); + SMC_RET1(handle, SMC_UNK); + default: + WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} + +/* Register PM Service Calls as runtime service */ +DECLARE_RT_SVC( + sip_svc, + OEN_SIP_START, + OEN_SIP_END, + SMC_TYPE_FAST, + sip_svc_setup, + sip_svc_smc_handler); diff --git a/plat/amd/versal2/soc_ipi.c b/plat/amd/versal2/soc_ipi.c new file mode 100644 index 000000000..85d1bcdd4 --- /dev/null +++ b/plat/amd/versal2/soc_ipi.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * SoC IPI agent registers access management + */ + +#include +#include + +/* versal2 ipi configuration table */ +static const struct ipi_config ipi_table[IPI_ID_MAX] = { + /* A78 IPI */ + [IPI_ID_APU] = { + .ipi_bit_mask = IPI0_TRIG_BIT, + .ipi_reg_base = IPI0_REG_BASE, + .secure_only = 0, + }, + + /* PMC IPI */ + [IPI_ID_PMC] = { + .ipi_bit_mask = PMC_IPI_TRIG_BIT, + .ipi_reg_base = IPI0_REG_BASE, + .secure_only = IPI_SECURE_MASK, + }, + + /* RPU0 IPI */ + [IPI_ID_RPU0] = { + .ipi_bit_mask = IPI1_TRIG_BIT, + .ipi_reg_base = IPI1_REG_BASE, + .secure_only = 0, + }, + + /* RPU1 IPI */ + [IPI_ID_RPU1] = { + .ipi_bit_mask = IPI2_TRIG_BIT, + .ipi_reg_base = IPI2_REG_BASE, + .secure_only = 0, + }, + + /* IPI3 IPI */ + [IPI_ID_3] = { + .ipi_bit_mask = IPI3_TRIG_BIT, + .ipi_reg_base = IPI3_REG_BASE, + .secure_only = 0, + }, + + /* IPI4 IPI */ + [IPI_ID_4] = { + .ipi_bit_mask = IPI4_TRIG_BIT, + .ipi_reg_base = IPI4_REG_BASE, + .secure_only = 0, + }, + + /* IPI5 IPI */ + [IPI_ID_5] = { + .ipi_bit_mask = IPI5_TRIG_BIT, + .ipi_reg_base = IPI5_REG_BASE, + .secure_only = 0, + }, +}; + +/** + * soc_ipi_config_table_init() - Initialize versal2 IPI configuration data. + */ +void soc_ipi_config_table_init(void) +{ + ipi_config_table_init(ipi_table, ARRAY_SIZE(ipi_table)); +} diff --git a/plat/amd/versal2/tsp/tsp-versal2.mk b/plat/amd/versal2/tsp/tsp-versal2.mk new file mode 100644 index 000000000..422ed1737 --- /dev/null +++ b/plat/amd/versal2/tsp/tsp-versal2.mk @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +# TSP source files specific to Versal Gen 2 platform + +PLAT_XILINX_COMMON := plat/xilinx/common/ + +include ${PLAT_XILINX_COMMON}/tsp/tsp.mk