SMMU: basic driver for init and probing
Introducing the driver in kernel for detecting SMMU features and initialise the hardware. Signed-off-by: Oliver Scott <Oliver.Scott@data61.csiro.au>
This commit is contained in:
parent
4fd7cb0360
commit
1a9756f65b
22 changed files with 668 additions and 37 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include <api/failures.h>
|
||||
#include <object/structures.h>
|
||||
|
||||
#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 */
|
||||
|
||||
|
||||
|
|
|
|||
306
include/drivers/smmu/smmuv2.h
Normal file
306
include/drivers/smmu/smmuv2.h
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <plat/machine/devices_gen.h>
|
||||
|
||||
/*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);
|
||||
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef CONFIG_ARM_SMMU
|
||||
#ifdef CONFIG_TK1_SMMU
|
||||
|
||||
#include <types.h>
|
||||
#include <plat/machine/hardware_gen.h>
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -45,11 +45,11 @@
|
|||
</interface>
|
||||
<interface name="seL4_ARM_IOPageTable" manual_name="I/O Page Table"
|
||||
cap_description="Capability to the I/O page table being operated on.">
|
||||
<method id="ARMIOPageTableMap" name="Map" condition="defined(CONFIG_ARM_SMMU)">
|
||||
<method id="ARMIOPageTableMap" name="Map" condition="defined(CONFIG_TK1_SMMU)">
|
||||
<param dir="in" name="iospace" type="seL4_ARM_IOSpace"/>
|
||||
<param dir="in" name="ioaddr" type="seL4_Word"/>
|
||||
</method>
|
||||
<method id="ARMIOPageTableUnmap" name="Unmap" condition="defined(CONFIG_ARM_SMMU)">
|
||||
<method id="ARMIOPageTableUnmap" name="Unmap" condition="defined(CONFIG_TK1_SMMU)">
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="seL4_ARM_Page" manual_name="Page"
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
Removes an existing mapping.
|
||||
</description>
|
||||
</method>
|
||||
<method id="ARMPageMapIO" name="MapIO" condition="defined(CONFIG_ARM_SMMU)" manual_name="Map I/O">
|
||||
<method id="ARMPageMapIO" name="MapIO" condition="defined(CONFIG_TK1_SMMU)" manual_name="Map I/O">
|
||||
<brief>
|
||||
|
||||
</brief>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef CONFIG_ARM_SMMU
|
||||
#ifdef CONFIG_TK1_SMMU
|
||||
|
||||
#include <api/syscall.h>
|
||||
#include <machine/io.h>
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
13
src/drivers/smmu/config.cmake
Normal file
13
src/drivers/smmu/config.cmake
Normal file
|
|
@ -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"
|
||||
)
|
||||
297
src/drivers/smmu/smmuv2.c
Normal file
297
src/drivers/smmu/smmuv2.c
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <types.h>
|
||||
#include <plat/machine/devices_gen.h>
|
||||
#include <drivers/smmu/smmuv2.h>
|
||||
|
||||
/*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();
|
||||
}
|
||||
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
#include <types.h>
|
||||
#include <config.h>
|
||||
|
||||
#ifdef CONFIG_ARM_SMMU
|
||||
#ifdef CONFIG_TK1_SMMU
|
||||
|
||||
#include <plat/machine/smmu.h>
|
||||
#include <linker.h>
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/interrupt-controller@3881000},
|
||||
&{/iommu@12000000},
|
||||
&{/timer};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue