123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- /*
- * Copyright (c) 2017-2024, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <common/debug.h>
- #include <cdefs.h>
- #include <drivers/arm/smmu_v3.h>
- #include <drivers/delay_timer.h>
- #include <lib/mmio.h>
- #include <arch_features.h>
- /* SMMU poll number of retries */
- #define SMMU_POLL_TIMEOUT_US U(1000)
- static int smmuv3_poll(uintptr_t smmu_reg, uint32_t mask,
- uint32_t value)
- {
- uint32_t reg_val;
- uint64_t timeout;
- /* Set 1ms timeout value */
- timeout = timeout_init_us(SMMU_POLL_TIMEOUT_US);
- do {
- reg_val = mmio_read_32(smmu_reg);
- if ((reg_val & mask) == value)
- return 0;
- } while (!timeout_elapsed(timeout));
- ERROR("Timeout polling SMMUv3 register @%p\n", (void *)smmu_reg);
- ERROR("Read value 0x%x, expected 0x%x\n", reg_val,
- value == 0U ? reg_val & ~mask : reg_val | mask);
- return -1;
- }
- /*
- * Abort all incoming transactions in order to implement a default
- * deny policy on reset.
- */
- int __init smmuv3_security_init(uintptr_t smmu_base)
- {
- /* Attribute update has completed when SMMU_(S)_GBPA.Update bit is 0 */
- if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U)
- return -1;
- /*
- * SMMU_(S)_CR0 resets to zero with all streams bypassing the SMMU,
- * so just abort all incoming transactions.
- */
- mmio_setbits_32(smmu_base + SMMU_GBPA,
- SMMU_GBPA_UPDATE | SMMU_GBPA_ABORT);
- if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U)
- return -1;
- /* Check if the SMMU supports secure state */
- if ((mmio_read_32(smmu_base + SMMU_S_IDR1) &
- SMMU_S_IDR1_SECURE_IMPL) == 0U)
- return 0;
- /* Abort all incoming secure transactions */
- if (smmuv3_poll(smmu_base + SMMU_S_GBPA, SMMU_S_GBPA_UPDATE, 0U) != 0U)
- return -1;
- mmio_setbits_32(smmu_base + SMMU_S_GBPA,
- SMMU_S_GBPA_UPDATE | SMMU_S_GBPA_ABORT);
- return smmuv3_poll(smmu_base + SMMU_S_GBPA, SMMU_S_GBPA_UPDATE, 0U);
- }
- /* Initialize the SMMU by invalidating all secure caches and TLBs. */
- int __init smmuv3_init(uintptr_t smmu_base)
- {
- /*
- * Initiate invalidation of secure caches and TLBs if the SMMU
- * supports secure state. If not, it's implementation defined
- * as to how SMMU_S_INIT register is accessed.
- * As per Arm SMMUv3 specification the SMMU_S_INIT register in a SMMU
- * with RME implementation has following properties:
- * a) all SMMU registers that are specified to be accessible only in
- * the Secure physical address space are additionally accessible in
- * Root physical address space.
- * b) as GPT information is permitted to be cached in a TLB, the
- * SMMU_S_INIT.INV_ALL operation also invalidates all GPT information
- * cached in TLBs.
- * Additionally, it is Root firmware’s responsibility to write to
- * INV_ALL before enabling SMMU_ROOT_CR0.{ACCESSEN,GPCEN}.
- */
- mmio_write_32(smmu_base + SMMU_S_INIT, SMMU_S_INIT_INV_ALL);
- /* Wait for global invalidation operation to finish */
- if (smmuv3_poll(smmu_base + SMMU_S_INIT,
- SMMU_S_INIT_INV_ALL, 0U) != 0) {
- return -1;
- }
- #if ENABLE_RME
- if (is_feat_rme_present()) {
- if ((mmio_read_32(smmu_base + SMMU_ROOT_IDR0) &
- SMMU_ROOT_IDR0_ROOT_IMPL) == 0U) {
- WARN("Skip SMMU GPC configuration.\n");
- } else {
- uint64_t gpccr_el3 = read_gpccr_el3();
- uint64_t gptbr_el3 = read_gptbr_el3();
- /* SMMU_ROOT_GPT_BASE_CFG[16] is RES0. */
- gpccr_el3 &= ~(1UL << 16);
- /*
- * TODO: SMMU_ROOT_GPT_BASE_CFG is 64b in the spec,
- * but SMMU model only accepts 32b access.
- */
- mmio_write_32(smmu_base + SMMU_ROOT_GPT_BASE_CFG,
- gpccr_el3);
- /*
- * pa_gpt_table_base[51:12] maps to GPTBR_EL3[39:0]
- * whereas it maps to SMMU_ROOT_GPT_BASE[51:12]
- * hence needs a 12 bit left shit.
- */
- mmio_write_64(smmu_base + SMMU_ROOT_GPT_BASE,
- gptbr_el3 << 12);
- /*
- * ACCESSEN=1: SMMU- and client-originated accesses are
- * not terminated by this mechanism.
- * GPCEN=1: All clients and SMMU-originated accesses,
- * except GPT-walks, are subject to GPC.
- */
- mmio_setbits_32(smmu_base + SMMU_ROOT_CR0,
- SMMU_ROOT_CR0_GPCEN |
- SMMU_ROOT_CR0_ACCESSEN);
- /* Poll for ACCESSEN and GPCEN ack bits. */
- if (smmuv3_poll(smmu_base + SMMU_ROOT_CR0ACK,
- SMMU_ROOT_CR0_GPCEN |
- SMMU_ROOT_CR0_ACCESSEN,
- SMMU_ROOT_CR0_GPCEN |
- SMMU_ROOT_CR0_ACCESSEN) != 0) {
- WARN("Failed enabling SMMU GPC.\n");
- /*
- * Do not return in error, but fall back to
- * invalidating all entries through the secure
- * register file.
- */
- }
- }
- }
- #endif /* ENABLE_RME */
- return 0;
- }
- int smmuv3_ns_set_abort_all(uintptr_t smmu_base)
- {
- /* Attribute update has completed when SMMU_GBPA.Update bit is 0 */
- if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U) {
- return -1;
- }
- /*
- * Set GBPA's ABORT bit. Other GBPA fields are presumably ignored then,
- * so simply preserve their value.
- */
- mmio_setbits_32(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE | SMMU_GBPA_ABORT);
- if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U) {
- return -1;
- }
- /* Disable the SMMU to engage the GBPA fields previously configured. */
- mmio_clrbits_32(smmu_base + SMMU_CR0, SMMU_CR0_SMMUEN);
- if (smmuv3_poll(smmu_base + SMMU_CR0ACK, SMMU_CR0_SMMUEN, 0U) != 0U) {
- return -1;
- }
- return 0;
- }
|