summaryrefslogtreecommitdiff
path: root/drivers/arm/smmu/smmu_v3.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/arm/smmu/smmu_v3.c')
-rw-r--r--drivers/arm/smmu/smmu_v3.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/arm/smmu/smmu_v3.c b/drivers/arm/smmu/smmu_v3.c
index a082a8107..de47febf6 100644
--- a/drivers/arm/smmu/smmu_v3.c
+++ b/drivers/arm/smmu/smmu_v3.c
@@ -13,7 +13,7 @@
/* SMMU poll number of retries */
#define SMMU_POLL_TIMEOUT_US U(1000)
-static int __init smmuv3_poll(uintptr_t smmu_reg, uint32_t mask,
+static int smmuv3_poll(uintptr_t smmu_reg, uint32_t mask,
uint32_t value)
{
uint32_t reg_val;
@@ -94,3 +94,45 @@ int __init smmuv3_init(uintptr_t smmu_base)
return smmuv3_poll(smmu_base + SMMU_S_INIT,
SMMU_S_INIT_INV_ALL, 0U);
}
+
+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;
+}
+
+int smmuv3_ns_set_bypass_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;
+
+ /* Clear GBPA's ABORT bit. Other GBPA fields are preserved. */
+ mmio_clrsetbits_32(smmu_base + SMMU_GBPA,
+ SMMU_GBPA_ABORT, SMMU_GBPA_UPDATE);
+ 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;
+}