diff --git a/configs/seL4Config.cmake b/configs/seL4Config.cmake index 2f41e35d5..76e7eb744 100644 --- a/configs/seL4Config.cmake +++ b/configs/seL4Config.cmake @@ -203,6 +203,7 @@ config_set(KernelArchArmV6 ARCH_ARM_V6 "${KernelArchArmV6}") config_set(KernelArchArmV7a ARCH_ARM_V7A "${KernelArchArmV7a}") config_set(KernelArchArmV7ve ARCH_ARM_V7VE "${KernelArchArmV7ve}") config_set(KernelArchArmV8a ARCH_ARM_V8A "${KernelArchArmV8a}") +config_set(KernelArmSMMU ARM_SMMU "${KernelArmSMMU}") set(KernelPlatformSupportsMCS "${KernelPlatformSupportsMCS}" CACHE INTERNAL "" FORCE) # Check for v7ve before v7a as v7ve is a superset and we want to set the diff --git a/include/arch/arm/arch/32/mode/object/structures.bf b/include/arch/arm/arch/32/mode/object/structures.bf index 076a95d94..6050bd762 100644 --- a/include/arch/arm/arch/32/mode/object/structures.bf +++ b/include/arch/arm/arch/32/mode/object/structures.bf @@ -23,7 +23,7 @@ block small_frame_cap { field_high capFMappedAddress 20 field capFIsDevice 1 -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU field capFIsIOSpace 1 field capFMappedASIDHigh 6 #else @@ -102,7 +102,7 @@ block vcpu_cap { } #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU -- IO space caps -- each module has an engine that can be enabled -- the clients use the same module can be separately enabled @@ -175,7 +175,7 @@ tagged_union cap capType { #endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */ -- we use the same names as for x86 IOMMU caps -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU tag io_space_cap 0x1f tag io_page_table_cap 0x2f #endif diff --git a/include/arch/arm/arch/32/mode/object/structures.h b/include/arch/arm/arch/32/mode/object/structures.h index e471cc31c..f6bb938df 100644 --- a/include/arch/arm/arch/32/mode/object/structures.h +++ b/include/arch/arm/arch/32/mode/object/structures.h @@ -298,7 +298,7 @@ static inline word_t CONST cap_get_archCapSizeBits(cap_t cap) case cap_vcpu_cap: return VCPU_SIZE_BITS; #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case cap_io_page_table_cap: return seL4_IOPageTableBits; #endif @@ -340,7 +340,7 @@ static inline bool_t CONST cap_get_archCapIsPhysical(cap_t cap) return true; #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case cap_io_page_table_cap: return true; #endif @@ -380,7 +380,7 @@ static inline void *CONST cap_get_archCapPtr(cap_t cap) return VCPU_PTR(cap_vcpu_cap_get_capVCPUPtr(cap)); #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case cap_io_page_table_cap: return (void *)(cap_io_page_table_cap_get_capIOPTBasePtr(cap)); #endif diff --git a/include/arch/arm/arch/object/interrupt.h b/include/arch/arm/arch/object/interrupt.h index c263a8609..7c2d637e8 100644 --- a/include/arch/arm/arch/object/interrupt.h +++ b/include/arch/arm/arch/object/interrupt.h @@ -39,7 +39,7 @@ static inline void handleReservedIRQ(irq_t irq) } #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU if (IRQT_TO_IRQ(irq) == INTERRUPT_SMMU) { plat_smmu_handle_interrupt(); return; diff --git a/include/arch/arm/arch/object/iospace.h b/include/arch/arm/arch/object/iospace.h index 56a6a38db..60ae90c13 100644 --- a/include/arch/arm/arch/object/iospace.h +++ b/include/arch/arm/arch/object/iospace.h @@ -10,7 +10,7 @@ #include #include -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU seL4_SlotRegion create_iospace_caps(cap_t root_cnode_cap); exception_t decodeARMIOPTInvocation(word_t invLabel, uint32_t length, cte_t *slot, cap_t cap, extra_caps_t excaps, @@ -65,6 +65,6 @@ static inline void clearIOPageDirectory(cap_t cap) { } -#endif /* end of !CONFIG_ARM_SMMU */ +#endif /* end of !CONFIG_TK1_SMMU */ diff --git a/include/drivers/smmu/smmuv2.h b/include/drivers/smmu/smmuv2.h new file mode 100644 index 000000000..d024cd80a --- /dev/null +++ b/include/drivers/smmu/smmuv2.h @@ -0,0 +1,306 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#pragma once + +#include + +/*the paddr address of the TX2 SMMU*/ +#define SMMU_TX2_PADDR 0x12000000 + +#define SMMU_PAGE_4KB 0x1000 +#define SMMU_PAGE_64KB 0x10000 + +/*the high-level physical address layout according to SMMU definition*/ +#define SMMU_GLOBAL_SIZE(num_page, page_size) ((num_page) * (page_size)) +#define SMMU_CB_SIZE(num_page, page_size) ((num_page) * (page_size)) +#define SMMU_CB_BASE_PADDR(global_size) (SMMU_TX2_PADDR + (global_size)) + +/*SMMU's physical address space layout, defined by SMMU v2 standard*/ +#define SMMU_GR0_PADDR SMMU_TX2_PADDR +#define SMMU_GR1_PADDR(page_size) ((SMMU_GR0_PADDR) + 1 * (page_size)) +#define SMMU_GID_PADDR(page_size) ((SMMU_GR0_PADDR) + 2 * (page_size)) +#define SMMU_PM_PADDR(page_size) ((SMMU_GR0_PADDR) + 3 * (page_size)) +#define SMMU_SSD_PADDR(page_size) ((SMMU_GR0_PADDR) + 4 * (page_size)) +#define SMMU_CBn_PADDR(cb_base, n ,page_size) ((cb_base) + n * (page_size)) + +/* SMMU's virtual address space layout in kernel address space, + * mapped by boot code.*/ +#define SMMU_GR0_PPTR SMMU_PPTR +#define SMMU_GR1_PPTR (SMMU_PPTR + 1 * (SMMU_PAGE_4KB)) +#define SMMU_GID_PPTR (SMMU_PPTR + 2 * (SMMU_PAGE_4KB)) +#define SMMU_PM_PPTR (SMMU_PPTR + 3 * (SMMU_PAGE_4KB)) +#define SMMU_SSD_PPTR (SMMU_PPTR + 4 * (SMMU_PAGE_4KB)) +#define SSMU_CB_BASE_PPTR (SMMU_PPTR + 5 * (SMMU_PAGE_4KB)) +#define SMMU_CBn_BASE_PPTR(n) ((SSMU_CB_BASE_PPTR) + (n) * (SMMU_PAGE_4KB)) + +/*global register space 0 registers*/ +#define SMMU_sCR0 0x000 +#define SMMU_SCR1 0x004 +#define SMMU_sCR2 0x008 +#define SMMU_sACR 0x010 +#define SMMU_IDR0 0x020 +#define SMMU_IDR1 0x024 +#define SMMU_IDR2 0x028 +#define SMMU_IDR3 0x02c +#define SMMU_IDR4 0x030 +#define SMMU_IDR5 0x034 +#define SMMU_IDR6 0x038 +#define SMMU_IDR7 0x03c +#define SMMU_sGFAR 0x040 +#define SMMU_sGFSR 0x048 +#define SMMU_sGFSRRESTORE 0x04c +#define SMMU_sGFSYNR0 0x050 +#define SMMU_sGFSYNR1 0x054 +#define SMMU_sGFSYNR2 0x058 +#define SMMU_STLBIALL 0x060 +#define SMMU_TLBIVMID 0x064 +#define SMMU_TLBIALLNSNH 0x068 +#define SMMU_TLBIALLH 0x06c +#define SMMU_sTLBGSYNC 0x070 +#define SMMU_sTLBGSTATUS 0x074 +#define SMMU_TLBIVAH 0x078 +#define SMMU_STLBIVALM 0x0a0 +#define SMMU_STLBIVAM 0x0a8 +#define SMMU_TLBIVALH64 0x0b0 +#define SMMU_TLBIVMIDS1 0x0b8 +#define SMMU_STLBIALLM 0x0bc +#define SMMU_TLBIVAH64 0x0c0 +#define SMMU_sGATS1UR 0x100 +#define SMMU_sGATS1UW 0x108 +#define SMMU_sGATS1PR 0x110 +#define SMMU_sGATS1PW 0x118 +#define SMMU_sGATS12UR 0x120 +#define SMMU_sGATS12UW 0x128 +#define SMMU_sGATS12PR 0x130 +#define SMMU_sGATS12PW 0x138 +#define SMMU_sGPAR 0x180 +#define SMMU_sGATSR 0x188 + +/*SMMU_SMRn, stream matching register 0 to 127*/ +#define SMMU_SMRn(n) (0x800 + (n) * 0x4) + +/*SMMU_S2CRn, stream-to-context register 0 to 127*/ +#define SMMU_S2CRn(n) (0xc00 + (n) * 0x4) + +/*global register space 1*/ +/*SMMU_CBARn, context bank attribute register 0 to 127*/ +#define SMMU_CBARn(n) (0x000 + (n) * 0x4) + +/*SMMU_CBFRSYNRAn, context bank fault restricted syndrome register A 0 to 127*/ +#define SMMU_CBFRSYNRAn(n) (0x400 + (n) * 0x4) + +/*SMMU_CBA2Rn, context bank attribute registers 0 to 127*/ +#define SMMU_CBA2Rn(n) (0x800 + (n) * 0x4) + +/*stage 1 and stage 2 translation context bank address space*/ +#define SMMU_CBn_SCTLR 0x000 +#define SMMU_CBn_ACTLR 0x004 +#define SMMU_CBn_RESUME 0x008 +#define SMMU_CBn_TCR2 0x010 +#define SMMU_CBn_TTBR0 0x020 +#define SMMU_CBn_TTBR1 0x028 +#define SMMU_CBn_TCR 0x030 +#define SMMU_CBn_CONTEXTIDR 0x034 + +/*the SMMU_CBn_MAIRm registers are used for AArch32 Long-descriptor or the AArch64*/ +#define SMMU_CBn_MAIR0 0x038 +#define SMMU_CBn_MAIR1 0x03c +/*the SMMU_CBn_PRRR and SMMU_CBn_NMRR registers are used for AArch32*/ +#define SMMU_CBn_PRRR 0x038 +#define SMMU_CBn_NMRR 0x03c + +#define SMMU_CBn_PAR 0x050 +#define SMMU_CBn_FSR 0x058 +#define SMMU_CBn_FSRRESTORE 0x05c +#define SMMU_CBn_FAR 0x060 +#define SMMU_CBn_FSYNR0 0x068 +#define SMMU_CBn_FSYNR1 0x06c +#define SMMU_CBn_IPAFAR 0x070 + +#define SMMU_CBn_TLBIVA 0x600 +#define SMMU_CBn_TLBIVAA 0x608 +#define SMMU_CBn_TLBIASID 0x610 +#define SMMU_CBn_TLBIALL 0x618 +#define SMMU_CBn_TLBIVAL 0x620 +#define SMMU_CBn_TLBIVAAL 0x628 +#define SMMU_CBn_TLBIIPAS2 0x630 +#define SMMU_CBn_TLBIIPAS2L 0x638 +#define SMMU_CBn_TLBSYNC 0x7f0 +#define SMMU_CBn_TLBSTATUS 0x7f4 + +/*SMMU_CR0 non-secure register 0 bit assignments*/ +#define CR0_VMID16EN BIT(31) +#define CR0_HYPMODE BIT(30) +#define CR0_WACFG (0x3 << 26) +#define CR0_RACFG (0x3 << 24) +#define CR0_SHCFG (0x3 << 22) +#define CR0_SMCFCFG BIT(21) +#define CR0_MTCFG BIT(20) +#define CR0_MemAttr (0xf << 16) +#define CR0_BSU (0x3 << 14) +#define CR0_FB BIT(13) +#define CR0_PTM BIT(12) +#define CR0_VMIDPNE BIT(11) +#define CR0_USFCFG BIT(10) +#define CR0_GSE BIT(9) +#define CR0_STALLD BIT(8) +#define CR0_TRANSIENTCFG (0x3 << 6) +#define CR0_GCFGFIE BIT(5) +#define CR0_GCFGFRE BIT(4) +#define CR0_EXIDENABLE BIT(3) +#define CR0_GFIE BIT(2) +#define CR0_GFRE BIT(1) +#define CR0_CLIENTPD BIT(0) + +/*SMMU_IDR0 (read only) read mask*/ +#define IDR0_SES BIT(31) +#define IDR0_S1TS BIT(30) +#define IDR0_S2TS BIT(29) +#define IDR0_NTS BIT(28) +#define IDR0_SMS BIT(27) +#define IDR0_ATOSNS BIT(26) +#define IDR0_PTFS (0x3 << 24) +#define IDR0_PTFS_VAL(v) ((v) >> 24) +#define IDR0_NUMIRPT (0xff << 16) +#define IDR0_NUMIRPT_VAL(v) ((v) >> 16) +#define IDR0_EXSMRGS BIT(15) +#define IDR0_CTTW BIT(14) +#define IDR0_BTM BIT(13) +#define IDR0_NUMSIDB (0xf << 9) +#define IDR0_NUMSIDB_VAL(v) ((v) >> 9) +#define IDR0_EXIDS BIT(8) +#define IDR0_NUMSMRG 0xff + +/*PTFS bits*/ +#define PTFS_AARCH32S_AARCH32L 0x0 +#define PTFS_AARCH32L_ONLY 0x1 +#define PTFS_NO_AARCH32 0x2 + +/*SMMU_IDR1 (read only) read mask*/ +#define IDR1_PAGESIZE BIT(31) +#define IDR1_NUMPAGENDXB (0x7 << 28) +#define IDR1_NUMPAGENDXB_VAL(v) ((v) >> 28) +#define IDR1_HAFDBS (0x3 << 24) +#define IDR1_NUMS2CB (0xff << 16) +#define IDR1_NUMS2CB_VAL(v) ((v) >> 16) +#define IDR1_SMCD BIT(15) +#define IDR1_SSDTP (0x3 << 12) +#define IDR1_NUMSSDNDXB (0xf << 8) +#define IDR1_NUMCB 0xff + +/*SMMU_IDR2 (read only) read mask*/ +#define IDR2_VMID16S BIT(15) +#define IDR2_PTFSV8_64 BIT(14) +#define IDR2_PTFSV8_16 BIT(13) +#define IDR2_PTFSV8_4 BIT(12) +#define IDR2_OAS (0xf << 4) +#define IDR2_OAS_VAL(v) ((v) >> 4) +#define IDR2_IAS 0xf + +/*OAS bits*/ +#define IDR2_OAS_32 0x0 +#define IDR2_OAS_36 0x1 +#define IDR2_OAS_40 0x2 +#define IDR2_OAS_42 0x3 +#define IDR2_OAS_44 0x4 +#define IDR2_OAS_48 0x5 + +/*IAS bits*/ +#define IDR2_IAS_32 0x0 +#define IDR2_IAS_36 0x1 +#define IDR2_IAS_40 0x2 +#define IDR2_IAS_42 0x3 +#define IDR2_IAS_44 0x4 +#define IDR2_IAS_48 0x5 + +/*SMMU_IDR7*/ +#define IDR7_MAJOR (0xf << 4) +#define IDR7_MAJOR_VAL(v) ((v) >> 4) +#define IDR7_MINOR (0xf) + +/*SMMU_sGFSR r/w bit mask, write 1 to clear*/ +#define GFSR_MULTI BIT(31) +#define GFSR_UUT BIT(8) +#define GFSR_PF BIT(7) +#define GFSR_EF BIT(6) +#define GFSR_CAF BIT(5) +#define GFSR_UCIF BIT(4) +#define GFSR_UCBF BIT(3) +#define GFSR_SMCF BIT(2) +#define GFSR_USF BIT(1) +#define GFSR_ICF BIT(0) + +/*SMMU_S2CRn, r/w bit mask for translation context*/ +#define S2CR_TRANSIENTCFG_SET(v) ((v) << 28) +#define S2CR_INSTCFG_SET(v) ((v) << 26) +#define S2CR_PRIVCFG_SET(v) ((v) << 24) +#define S2CR_WACFG_SET(v) ((v) << 22) +#define S2CR_RACFG_SET(v) ((v) << 20) +#define S2CR_NSCFG_SET(v) ((v) << 18) +#define S2CR_TYPE_SET(v) ((v) << 16) +#define S2CR_MemAttr_SET(v) ((v) << 12) +#define S2CR_MTCFG_SET(v) ((v) << 11) +#define S2CR_EXIDVALID_SET(v) ((v) << 10) +#define S2CR_SHCFG_SET(v) ((v) << 8) +#define S2CR_CBNDX_SET(v) ((v) & 0xff) + +/*SMMU_S2CRn PRIVCFG values*/ +#define S2CR_PRIVCFG_DEFAULT 0x0 + +/*SMMU_S2CRn type values*/ +#define S2CR_TYPE_CB 0x0 +#define S2CR_TYPE_BYPASS 0x1 +#define S2CR_TYPE_FAULT 0x2 + +/*SMMU_SMRn, r/w bit mask for stream match*/ +#define SMR_VALID_SET(v) ((v) << 30) +#define SMR_MASK_SET(v) ((v) << 16) +#define SMR_ID_SET(v) ((v) & 0x7fff) +/*valid /invalid*/ +#define SMR_VALID_EN 0x1 +#define SMR_VALID_DIS 0x0 + +/*SMMU_ACR, SMMU-500*/ +#define ACR_CACHE_LOCK BIT(26) +#define ACR_S2CRB_TLBEN BIT(10) +#define ACR_SMTNMB_TLBEN BIT(8) + +/*SMMU_CBn_FSR, write 1 to clear*/ +#define CBn_FSR_MULTI BIT(31) +#define CBn_FSR_SS BIT(30) +#define CBn_FSR_UUT BIT(8) +#define CBn_FSR_ASF BIT(7) +#define CBn_FSR_TLBLKF BIT(6) +#define CBn_FSR_TLBLMCF BIT(5) +#define CBn_FSR_EF BIT(4) +#define CBn_FSR_PF BIT(3) +#define CBn_FSR_AFF BIT(2) +#define CBn_FSR_TF BIT(1) + +#define CBn_FSR_CLEAR_ALL (CBn_FSR_MULTI | CBn_FSR_SS | \ + CBn_FSR_UUT | CBn_FSR_ASF | CBn_FSR_TLBLKF | \ + CBn_FSR_TLBLMCF | CBn_FSR_EF | CBn_FSR_PF | \ + CBn_FSR_AFF | CBn_FSR_TF) + +/*SMMU_CBn_ACTLR defined in SMMU500*/ +#define CBn_ACTLR_CPRE BIT(1) +#define CBn_ACTLR_CMTLB BIT(0) + +/*mask for invalidate all TLB entries, used by GR0 registers*/ +#define SMMU_TLB_INVALL_MASK 0xffffffff + +/*mask for init the TLB sync msg*/ +#define SMMU_TLB_SYNC_MASK 0xffffffff + +/*TLB sync status used in SMMU_sTLBGSTATUS and SMMU_CBn_TLBSTATUS*/ +#define TLBSTATUS_GSACTIVE BIT(0) +/*the kernel loops N times before declear a TLB invalidation failure*/ +#define TLBSYNC_LOOP 1000 + + +void plat_smmu_init(void); + diff --git a/include/plat/tk1/plat/machine/smmu.h b/include/plat/tk1/plat/machine/smmu.h index 9cea3f0e8..4a1d1dd39 100644 --- a/include/plat/tk1/plat/machine/smmu.h +++ b/include/plat/tk1/plat/machine/smmu.h @@ -8,7 +8,7 @@ #include -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU #include #include @@ -157,7 +157,7 @@ void plat_smmu_ptc_flush_all(void); iopde_t *plat_smmu_lookup_iopd_by_asid(uint32_t asid); void plat_smmu_handle_interrupt(void); -#else /* !CONFIG_ARM_SMMU */ +#else /* !CONFIG_TK1_SMMU */ /* dummy functions */ static inline void plat_smmu_handle_interrupt(void) @@ -165,5 +165,5 @@ static inline void plat_smmu_handle_interrupt(void) return; } -#endif /* CONFIG_ARM_SMMU */ +#endif /* CONFIG_TK1_SMMU */ diff --git a/libsel4/arch_include/arm/interfaces/sel4arch.xml b/libsel4/arch_include/arm/interfaces/sel4arch.xml index e9120f94c..e7e74c341 100644 --- a/libsel4/arch_include/arm/interfaces/sel4arch.xml +++ b/libsel4/arch_include/arm/interfaces/sel4arch.xml @@ -45,11 +45,11 @@ - + - + - + diff --git a/libsel4/arch_include/arm/sel4/arch/objecttype.h b/libsel4/arch_include/arm/sel4/arch/objecttype.h index 1523e58f3..31f2b9f5a 100644 --- a/libsel4/arch_include/arm/sel4/arch/objecttype.h +++ b/libsel4/arch_include/arm/sel4/arch/objecttype.h @@ -22,7 +22,7 @@ typedef enum _object { #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT seL4_ARM_VCPUObject, #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU seL4_ARM_IOPageTableObject, #endif seL4_ObjectTypeCount @@ -34,7 +34,7 @@ typedef seL4_Word object_t; #define seL4_ARM_VCPUObject 0xfffe #endif -#ifndef CONFIG_ARM_SMMU +#ifndef CONFIG_TK1_SMMU #define seL4_ARM_IOPageTableObject 0xffff #endif diff --git a/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h b/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h index 15b50d5bc..ece1ceb97 100644 --- a/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h +++ b/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h @@ -215,7 +215,7 @@ typedef enum { #define seL4_PageDirBits 14 #define seL4_VSpaceBits seL4_PageDirBits -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU #define seL4_NumASIDPoolsBits 6 #else #define seL4_NumASIDPoolsBits 7 diff --git a/src/arch/arm/32/kernel/vspace.c b/src/arch/arm/32/kernel/vspace.c index bc2163968..d1024bfc2 100644 --- a/src/arch/arm/32/kernel/vspace.c +++ b/src/arch/arm/32/kernel/vspace.c @@ -478,7 +478,7 @@ static BOOT_CODE cap_t create_it_frame_cap(pptr_t pptr, vptr_t vptr, asid_t asid wordFromVMRights(VMReadWrite), /* capFVMRights */ vptr, /* capFMappedAddress */ false, /* capFIsDevice */ -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU 0, /* IOSpace */ #endif ASID_HIGH(asid), /* capFMappedASIDHigh */ @@ -1031,7 +1031,7 @@ bool_t CONST isValidVTableRoot(cap_t cap) bool_t CONST isIOSpaceFrameCap(cap_t cap) { -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU return cap_get_capType(cap) == cap_small_frame_cap && cap_small_frame_cap_get_capFIsIOSpace(cap); #else return false; @@ -2427,7 +2427,7 @@ static exception_t decodeARMFrameInvocation(word_t invLabel, word_t length, } case ARMPageUnmap: { -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU if (isIOSpaceFrameCap(cap)) { setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); return performPageInvocationUnmapIO(cap, cte); @@ -2439,7 +2439,7 @@ static exception_t decodeARMFrameInvocation(word_t invLabel, word_t length, } } -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case ARMPageMapIO: { return decodeARMIOMapInvocation(invLabel, length, cte, cap, excaps, buffer); } diff --git a/src/arch/arm/32/object/objecttype.c b/src/arch/arm/32/object/objecttype.c index b5ae000f2..3e005cefc 100644 --- a/src/arch/arm/32/object/objecttype.c +++ b/src/arch/arm/32/object/objecttype.c @@ -87,7 +87,7 @@ deriveCap_ret_t Arch_deriveCap(cte_t *slot, cap_t cap) return ret; #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case cap_io_space_cap: ret.cap = cap; ret.status = EXCEPTION_NONE; @@ -170,7 +170,7 @@ finaliseCap_ret_t Arch_finaliseCap(cap_t cap, bool_t final) case cap_small_frame_cap: if (cap_small_frame_cap_get_capFMappedASID(cap)) { -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU if (isIOSpaceFrameCap(cap)) { unmapIOPage(cap); break; @@ -225,7 +225,7 @@ finaliseCap_ret_t Arch_finaliseCap(cap_t cap, bool_t final) break; #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case cap_io_space_cap: if (final) { clearIOPageDirectory(cap); @@ -300,7 +300,7 @@ bool_t CONST Arch_sameRegionAs(cap_t cap_a, cap_t cap_b) break; #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case cap_io_space_cap: if (cap_get_capType(cap_b) == cap_io_space_cap) { return cap_io_space_cap_get_capModuleID(cap_a) == @@ -362,7 +362,7 @@ word_t Arch_getObjectSize(word_t t) return PTE_SIZE_BITS + PT_INDEX_BITS; case seL4_ARM_PageDirectoryObject: return PDE_SIZE_BITS + PD_INDEX_BITS; -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case seL4_ARM_IOPageTableObject: return seL4_IOPageTableBits; #endif @@ -396,7 +396,7 @@ cap_t Arch_createObject(object_t t, void *regionBase, word_t userSize, bool_t de return cap_small_frame_cap_new( ASID_LOW(asidInvalid), VMReadWrite, 0, !!deviceMemory, -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU 0, #endif ASID_HIGH(asidInvalid), @@ -514,7 +514,7 @@ cap_t Arch_createObject(object_t t, void *regionBase, word_t userSize, bool_t de return cap_vcpu_cap_new(VCPU_REF(regionBase)); #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case seL4_ARM_IOPageTableObject: /* When the untyped was zeroed it was cleaned to the PoU, but the SMMUs * typically pull directly from RAM, so we do a futher clean to RAM here */ @@ -540,9 +540,9 @@ exception_t Arch_decodeInvocation(word_t invLabel, word_t length, cptr_t cptr, /* The C parser cannot handle a switch statement with only a default * case. So we need to do some gymnastics to remove the switch if * there are no other cases */ -#if defined(CONFIG_ARM_SMMU) || defined(CONFIG_ARM_HYPERVISOR_SUPPORT) +#if defined(CONFIG_TK1_SMMU) || defined(CONFIG_ARM_HYPERVISOR_SUPPORT) switch (cap_get_capType(cap)) { -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU case cap_io_space_cap: return decodeARMIOSpaceInvocation(invLabel, cap); case cap_io_page_table_cap: diff --git a/src/arch/arm/config.cmake b/src/arch/arm/config.cmake index 111b98289..a0dc61cc8 100644 --- a/src/arch/arm/config.cmake +++ b/src/arch/arm/config.cmake @@ -114,7 +114,13 @@ config_option( ) config_option( - KernelArmSMMU ARM_SMMU "Enable SystemMMU for the Tegra TK1 SoC" + KernelArmSMMU ARM_SMMU "Enable SystemMMU" + DEFAULT OFF + DEPENDS "KernelPlatformTx2" +) + +config_option( + KernelTk1SMMU TK1_SMMU "Enable SystemMMU for the Tegra TK1 SoC" DEFAULT OFF DEPENDS "KernelPlatformTK1" ) diff --git a/src/arch/arm/kernel/boot.c b/src/arch/arm/kernel/boot.c index 46f3be42c..b9cc00a23 100644 --- a/src/arch/arm/kernel/boot.c +++ b/src/arch/arm/kernel/boot.c @@ -98,7 +98,7 @@ BOOT_CODE static void init_irqs(cap_t root_cnode_cap) setIRQState(IRQReserved, CORE_IRQ_TO_IRQT(0, INTERRUPT_VGIC_MAINTENANCE)); setIRQState(IRQReserved, CORE_IRQ_TO_IRQT(0, INTERRUPT_VTIMER_EVENT)); #endif -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU setIRQState(IRQReserved, CORE_IRQ_TO_IRQT(0, INTERRUPT_SMMU)); #endif @@ -225,6 +225,9 @@ BOOT_CODE static void init_plat(void) { initIRQController(); initL2Cache(); +#ifdef CONFIG_ARM_SMMU + plat_smmu_init(); +#endif } #ifdef ENABLE_SMP_SUPPORT @@ -397,7 +400,7 @@ static BOOT_CODE bool_t try_init_kernel( *(seL4_BootInfoHeader *)(rootserver.extra_bi + extra_bi_offset) = header; } - if (config_set(CONFIG_ARM_SMMU)) { + if (config_set(CONFIG_TK1_SMMU)) { ndks_boot.bi_frame->ioSpaceCaps = create_iospace_caps(root_cnode_cap); if (ndks_boot.bi_frame->ioSpaceCaps.start == 0 && ndks_boot.bi_frame->ioSpaceCaps.end == 0) { diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index 70a78920a..cc43a0fad 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -6,7 +6,7 @@ #include -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU #include #include @@ -475,4 +475,4 @@ exception_t decodeARMIOSpaceInvocation(word_t invLabel, cap_t cap) current_syscall_error.type = seL4_IllegalOperation; return EXCEPTION_SYSCALL_ERROR; } -#endif /* end of CONFIG_ARM_SMMU */ +#endif /* end of CONFIG_TK1_SMMU */ diff --git a/src/drivers/config.cmake b/src/drivers/config.cmake index 4cda25fb4..04f536d9e 100644 --- a/src/drivers/config.cmake +++ b/src/drivers/config.cmake @@ -17,4 +17,5 @@ macro(register_driver compatibility_strings match_strings) endmacro() include(src/drivers/serial/config.cmake) +include(src/drivers/smmu/config.cmake) include(src/drivers/timer/config.cmake) diff --git a/src/drivers/smmu/config.cmake b/src/drivers/smmu/config.cmake new file mode 100644 index 000000000..6f97fd9c6 --- /dev/null +++ b/src/drivers/smmu/config.cmake @@ -0,0 +1,13 @@ +# +# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) +# +# SPDX-License-Identifier: GPL-2.0-only +# + +cmake_minimum_required(VERSION 3.7.2) + +register_driver( + compatibility_strings "arm,mmu-500" + PREFIX src/drivers/smmu + CFILES "smmuv2.c" +) \ No newline at end of file diff --git a/src/drivers/smmu/smmuv2.c b/src/drivers/smmu/smmuv2.c new file mode 100644 index 000000000..f1869d08f --- /dev/null +++ b/src/drivers/smmu/smmuv2.c @@ -0,0 +1,297 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: GPL-2.0-only + */ +#include +#include +#include +#include + +/*supported stages of translations*/ +#define STAGE1_TRANS (1 << 0) +#define STAGE2_TRANS (1 << 1) +#define NESTED_TRANS (1 << 2) +/*supported translation table formats*/ +#define AARCH32S_FMT (1 << 0) +#define AARCH32L_FMT (1 << 1) +#define NO_AARCH32_FMT (1 << 2) +#define TRANS_PAGES_4KB (1 << 3) +#define TRANS_PAGES_16KB (1 << 4) +#define TRANS_PAGES_64KB (1 << 5) + +struct smmu_feature { + bool_t stream_match; /*stream match register funtionality included*/ + bool_t trans_op; /*address translation operations supported*/ + bool_t cotable_walk; /*coherent translation table walk*/ + bool_t broadcast_tlb; /*broadcast TLB maintenance*/ + bool_t vmid16; /*16 bits VMIDs are supported*/ + uint32_t supported_trans; /*supported translation stages*/ + uint32_t supported_fmt; /*supported translation formats*/ + uint32_t num_cfault_ints; /*supported number of context fault interrupts*/ + uint32_t num_stream_ids; /*number of stream IDs*/ + uint32_t num_stream_map_groups; /*num stream mapping register groups*/ + uint32_t smmu_page_size; /*page size in SMMU register address space*/ + uint32_t smmu_num_pages; /*number of pages in global or context bank address space*/ + uint32_t num_s2_cbanks; /*cbanks that support stage 2 only*/ + uint32_t num_cbanks; /*total number of context banks*/ + uint32_t pa_size; /*PA address size*/ + uint32_t ipa_size; /*IPA address size*/ + pptr_t cb_base; /*base of context bank address space*/ +}; + +static struct smmu_feature smmu_dev_knowledge; + +static inline uint32_t smmu_read_reg32(pptr_t base, uint32_t index) +{ + return *(volatile uint32_t*)(base + index); +} + +static inline void smmu_write_reg32(pptr_t base, uint32_t index, uint32_t val) +{ + *(volatile uint32_t*) (base + index) = val; +} + +static inline uint64_t smmu_read_reg64(pptr_t base, uint32_t index) +{ + return *(volatile uint64_t*) (base + index); +} + +static inline void smmu_write_reg64(pptr_t base, uint32_t index, uint64_t val) +{ + *(volatile uint64_t *) (base + index) = val; +} + +static void smmu_tlb_sync(pptr_t base, uint32_t sync, uint32_t status) +{ + int count = 0; + smmu_write_reg32(base, sync, SMMU_TLB_SYNC_MASK); + while (count < TLBSYNC_LOOP) { + /*pulling the active flag, reading the TLB command state.*/ + if (!(smmu_read_reg32(base, status) & TLBSTATUS_GSACTIVE)) + break; + count++; + } +} + +BOOT_CODE static void smmu_mapping_init(void) +{ + /*Creating mapping for the rest of SMMU address space. + * the code assumes registers in each SMMU page are located in a 4K page + * even though the alignement of the (physical) pages can be 64K. + * We make this assumption to compact the SMMU virtual address window.*/ + + /* This is a temporary solution. A correct solution should be adjust + * the virutal address space layout of the kernel, leaving enough virtual + * address space to SMMU windows. For example, SMMU on TX2 requires a 8M space + * in total, including those empty areas resulted from the 64K alignment. + * Also, kernel requires device space to be configured statically. To + * support populate device space using HW config, we need to modify + * kernel_frame_t and map_kernel_frame, allowing devices mapped in a + * seperate page table using HW config.*/ + + /*the current implementation has been only tested on the TX2 platform*/ + + /*init the GR1 region, start: smmu_pptr + 4K, size 4K*/ + map_kernel_frame(SMMU_GR1_PADDR(smmu_dev_knowledge.smmu_page_size), + SMMU_GR1_PPTR, + VMKernelOnly, + vm_attributes_new(true, false, false)); + /*GID registers*/ + map_kernel_frame(SMMU_GID_PADDR(smmu_dev_knowledge.smmu_page_size), + SMMU_GID_PPTR, + VMKernelOnly, + vm_attributes_new(true, false, false)); + /*PM registers*/ + map_kernel_frame(SMMU_PM_PADDR(smmu_dev_knowledge.smmu_page_size), + SMMU_PM_PPTR, + VMKernelOnly, + vm_attributes_new(true, false, false)); + /*SSD registers*/ + map_kernel_frame(SMMU_SSD_PADDR(smmu_dev_knowledge.smmu_page_size), + SMMU_SSD_PPTR, + VMKernelOnly, + vm_attributes_new(true, false, false)); + /*map the context banks, each bank maps to a 4K page*/ + for (int i = 0; i < smmu_dev_knowledge.num_cbanks; i++) { + map_kernel_frame(SMMU_CBn_PADDR(smmu_dev_knowledge.cb_base, i, smmu_dev_knowledge.smmu_page_size), + SMMU_CBn_BASE_PPTR(i), + VMKernelOnly, + vm_attributes_new(true, false, false)); + } +} + +BOOT_CODE static void smmu_config_prob(void) +{ + uint32_t reg, field; + /*ID0*/ + reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_IDR0); + /*stages supported*/ + if (reg & IDR0_S1TS) + smmu_dev_knowledge.supported_trans |= STAGE1_TRANS; + if (reg & IDR0_S2TS) + smmu_dev_knowledge.supported_trans |= STAGE2_TRANS; + if (reg & IDR0_NTS) + smmu_dev_knowledge.supported_trans |= NESTED_TRANS; + /*stream matching register*/ + if (reg & IDR0_SMS) + smmu_dev_knowledge.stream_match = true; + /*address translation operation*/ + if ((reg & IDR0_ATOSNS) == 0) + smmu_dev_knowledge.trans_op = true; + /*AARCH32 translation format support*/ + field = IDR0_PTFS_VAL(reg & IDR0_PTFS); + if (field == PTFS_AARCH32S_AARCH32L) { + smmu_dev_knowledge.supported_fmt |= AARCH32L_FMT; + smmu_dev_knowledge.supported_fmt |= AARCH32S_FMT; + } else if (field == PTFS_AARCH32L_ONLY) { + smmu_dev_knowledge.supported_fmt |= AARCH32L_FMT; + } else { + smmu_dev_knowledge.supported_fmt |= NO_AARCH32_FMT; + } + /*number of context fault intrrupts + * However, in smmuv2, each context bank has dedicated interrupt pin + * hence no requirement to specify implemented interrupts here.*/ + smmu_dev_knowledge.num_cfault_ints = IDR0_NUMIRPT_VAL(reg & IDR0_NUMIRPT); + /*coherent translation table walk*/ + if (reg & IDR0_CTTW) + smmu_dev_knowledge.cotable_walk = true; + /*broadcast TLB maintenance*/ + if (reg & IDR0_BTM) + smmu_dev_knowledge.broadcast_tlb = true; + /*number of stream IDs*/ + smmu_dev_knowledge.num_stream_ids = (1 << IDR0_NUMSIDB_VAL(reg & IDR0_NUMSIDB)) - 1; + /*number of stream mapping register groups*/ + smmu_dev_knowledge.num_stream_map_groups = reg & IDR0_NUMSMRG; + + /*ID1*/ + reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_IDR1); + /*smmu page size*/ + if (reg & IDR1_PAGESIZE ) + smmu_dev_knowledge.smmu_page_size = SMMU_PAGE_64KB; + else + smmu_dev_knowledge.smmu_page_size = SMMU_PAGE_4KB; + /*smmu num pages, 2^(numdxb + 1)*/ + field = IDR1_NUMPAGENDXB_VAL(reg & IDR1_NUMPAGENDXB); + smmu_dev_knowledge.smmu_num_pages = 1 << (field + 1); + /*num of stage 2 context banks*/ + smmu_dev_knowledge.num_s2_cbanks = IDR1_NUMS2CB_VAL(reg & IDR1_NUMS2CB); + /*total num of context banks*/ + smmu_dev_knowledge.num_cbanks = reg & IDR1_NUMCB; + /*calcuate the context bank base*/ + smmu_dev_knowledge.cb_base = SMMU_CB_BASE_PADDR( + SMMU_GLOBAL_SIZE(smmu_dev_knowledge.smmu_num_pages, smmu_dev_knowledge.smmu_page_size)); + + /*ID2*/ + reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_IDR2); + /*VNID16S*/ + if (reg & IDR2_VMID16S) + smmu_dev_knowledge.vmid16 = true; + /*PTFSV8_64KB*/ + if (reg & IDR2_PTFSV8_64) + smmu_dev_knowledge.supported_fmt |= TRANS_PAGES_64KB; + /*PTFSV8_16KB*/ + if (reg & IDR2_PTFSV8_16) + smmu_dev_knowledge.supported_fmt |= TRANS_PAGES_16KB; + /*PTFSV8_64KB*/ + if (reg & IDR2_PTFSV8_4) + smmu_dev_knowledge.supported_fmt |= TRANS_PAGES_4KB; + /*OAS*/ + smmu_dev_knowledge.pa_size = IDR2_OAS_VAL(reg & IDR2_OAS); + /*IAS*/ + smmu_dev_knowledge.ipa_size = reg & IDR2_IAS; +} + + +BOOT_CODE static void smmu_dev_reset(void) +{ + uint32_t reg; + pptr_t cb_bank_ptr; + uint32_t major; + + /*clear the global FSR by writing back the read value*/ + reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sGFSR); + smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sGFSR, reg); + + /*reset stream to context config as using context banks*/ + reg = S2CR_PRIVCFG_SET(S2CR_PRIVCFG_DEFAULT); + reg |= S2CR_TYPE_SET(S2CR_TYPE_CB); + + /*the number of stream-to-context is realted to the stream indexing method*/ + if (smmu_dev_knowledge.stream_match) { + /*stream matching*/ + for (int i = 0; i < smmu_dev_knowledge.num_stream_map_groups; i++) + smmu_write_reg32(SMMU_GR0_PPTR, SMMU_S2CRn(i), reg); + /*reset the stream match registers as invalid*/ + reg = SMR_VALID_SET(SMR_VALID_DIS); + for (int i = 0; i < smmu_dev_knowledge.num_stream_map_groups; i++) + smmu_write_reg32(SMMU_GR0_PPTR, SMMU_SMRn(i), reg); + } else { + /*stream ID*/ + for (int i = 0; i < smmu_dev_knowledge.num_stream_ids; i++) + smmu_write_reg32(SMMU_GR0_PPTR, SMMU_S2CRn(i), reg); + } + + /*special init requested by the smmu-500: start*/ + reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_IDR7); + major = IDR7_MAJOR_VAL(reg & IDR7_MAJOR); + /*init the auxiliary configuration register*/ + reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sACR); + /*unlock the write access to SMMU_CBn_ACTLR, + only provided in version 2 and above*/ + if (major >= 2) + reg &= ~ACR_CACHE_LOCK; + /*enable the TLB to cache bypassing*/ + reg |= ACR_S2CRB_TLBEN | ACR_SMTNMB_TLBEN; + smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sACR, reg); + /*special init requested by the smmu-500: end*/ + + for (int i = 0; i < smmu_dev_knowledge.num_cbanks; i++) { + cb_bank_ptr = SMMU_CBn_BASE_PPTR(i); + /*disable context banks and clear the context bank fault registers*/ + smmu_write_reg32(cb_bank_ptr, SMMU_CBn_SCTLR, 0); + smmu_write_reg32(cb_bank_ptr, SMMU_CBn_FSR, CBn_FSR_CLEAR_ALL); + + /*special init requested by the smmu-500: start*/ + /*disable MMU-500's next page prefetch due to errata 841119 and 826419*/ + reg = smmu_read_reg32(cb_bank_ptr, SMMU_CBn_ACTLR); + reg &= ~CBn_ACTLR_CPRE; + smmu_write_reg32(cb_bank_ptr, SMMU_CBn_ACTLR, reg); + /*special init requested by the smmu-500: end*/ + } + + /*invalidate TLB */ + smmu_write_reg32(SMMU_GR0_PPTR, SMMU_TLBIALLH, SMMU_TLB_INVALL_MASK); + smmu_write_reg32(SMMU_GR0_PPTR, SMMU_TLBIALLNSNH, SMMU_TLB_INVALL_MASK); + + reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sCR0); + /*enable global fault reporting*/ + reg |= CR0_GFRE | CR0_GFIE | CR0_GCFGFRE | CR0_GCFGFIE; + /*raise fault for any transaction that does not match to + any stream mapping table entires*/ + reg |= CR0_USFCFG; + /*raise fault for stream match conflict*/ + reg |= CR0_SMCFCFG; + /*disable the VMID private name space*/ + reg &= ~CR0_VMIDPNE; + /*TLB is maintained together with the rest of the system*/ + reg &= ~CR0_PTM; + /*enable force TLB broadcast on bypassing transactions*/ + reg |= CR0_FB; + /*enable client access, ie transaction enforced by SMMU*/ + reg &= ~CR0_CLIENTPD; + /*Not upgrade barrier*/ + reg &= ~CR0_BSU; + /*syn above issued TLB operations*/ + smmu_tlb_sync(SMMU_GR0_PPTR, SMMU_sTLBGSYNC, SMMU_sTLBGSTATUS); + /*enable the SMMU*/ + smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sCR0, reg); +} + +BOOT_CODE void plat_smmu_init(void) +{ + smmu_config_prob(); + smmu_mapping_init(); + smmu_dev_reset(); +} + diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c index 4ebf56b8d..d9b59a293 100644 --- a/src/plat/tk1/machine/smmu.c +++ b/src/plat/tk1/machine/smmu.c @@ -7,7 +7,7 @@ #include #include -#ifdef CONFIG_ARM_SMMU +#ifdef CONFIG_TK1_SMMU #include #include diff --git a/src/plat/tx2/config.cmake b/src/plat/tx2/config.cmake index 476a56344..9419654f1 100644 --- a/src/plat/tx2/config.cmake +++ b/src/plat/tx2/config.cmake @@ -14,6 +14,7 @@ if(KernelPlatformTx2) # the 44-bit PA for Cortex-A57 cores would need to be downgraded to 40bit. set(KernelArmCortexA57 ON) set(KernelArchArmV8a ON) + set(KernelArmSMMU ON) config_set(KernelARMPlatform ARM_PLAT tx2) config_set(KernelArmMach MACH "nvidia") list(APPEND KernelDTSList "tools/dts/tx2.dts") @@ -27,6 +28,7 @@ if(KernelPlatformTx2) CLK_SHIFT 57u CLK_MAGIC 4611686019u KERNEL_WCET 10u + SMMU drivers/smmu/smmuv2.h ) endif() diff --git a/src/plat/tx2/overlay-tx2.dts b/src/plat/tx2/overlay-tx2.dts index ccb872645..1721005f8 100644 --- a/src/plat/tx2/overlay-tx2.dts +++ b/src/plat/tx2/overlay-tx2.dts @@ -14,6 +14,7 @@ seL4,kernel-devices = "serial0", &{/interrupt-controller@3881000}, + &{/iommu@12000000}, &{/timer}; }; diff --git a/tools/hardware.yml b/tools/hardware.yml index d321dbb45..5dc808549 100644 --- a/tools/hardware.yml +++ b/tools/hardware.yml @@ -117,6 +117,7 @@ devices: # Tegra SMMU (memory-controllers/nvidia,tegra30-mc.txt) - compatible: - nvidia,tegra124-mc + - arm,mmu-500 regions: - index: 0 kernel: SMMU_PPTR