1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "mmu500.h"
9 
10 #include <mod_synquacer_system.h>
11 
12 #include <fwk_log.h>
13 
14 #include <inttypes.h>
15 
SMMU_setup_PMU(MMU500_Type_t * SMMU)16 void SMMU_setup_PMU(MMU500_Type_t *SMMU)
17 {
18     volatile uint32_t *pmu_regs;
19     int page_size;
20 
21     page_size = ((SMMU->GR0.IDR1 & SMMU_IDR1_PAGESIZE) == 0) ? 0x1000 : 0x10000;
22 
23     pmu_regs = (volatile uint32_t *)(((uint32_t)SMMU) + 3 * page_size);
24 
25     pmu_regs[0x0400 / 4] =
26         0x00000010U; /* PMEVTYPER0: P=U=NSP=NSU=0, EVENT=0x0010(access)  */
27     pmu_regs[0x0404 / 4] =
28         0x00000011U; /* PMEVTYPER1: P=U=NSP=NSU=0, EVENT=0x0011(read)    */
29     pmu_regs[0x0408 / 4] =
30         0x00000012U; /* PMEVTYPER2: P=U=NSP=NSU=0, EVENT=0x0012(write)   */
31     pmu_regs[0x0c00 / 4] =
32         0x00000007U; /* PMCNTENSET0: enable counter #0, #1, #2           */
33     pmu_regs[0x0800 / 4] = 0x00000800U; /* PMCGCR0: enable=1, global_basis */
34     pmu_regs[0x0e04 / 4] = 0x00000003U; /* PMCR: enable=1, reset=1 */
35 
36     FWK_LOG_INFO(
37         "[MMU500] setup PMU for MMU-500@0x%08" PRIx32
38         ". page_size=%d. 0x%08" PRIx32 "(access), 0x%08" PRIx32
39         "(read), 0x%08" PRIx32 "(write).",
40         (uint32_t)SMMU,
41         page_size,
42         (uint32_t)&pmu_regs[0],
43         (uint32_t)&pmu_regs[1],
44         (uint32_t)&pmu_regs[2]);
45 }
46 
SMMU_s_init(MMU500_Type_t * SMMU,uint32_t num_context,const MMU500_ContextInfo_t * context_info,enum mmu500_granule granule)47 int32_t SMMU_s_init(
48     MMU500_Type_t *SMMU,
49     uint32_t num_context,
50     const MMU500_ContextInfo_t *context_info,
51     enum mmu500_granule granule)
52 {
53     uint32_t temp;
54     uint32_t i;
55 
56     SMMU->GR0.ACR |=
57         SMMU_ACR_S2CRB_TLBEN | SMMU_ACR_MMUDISB_TLBEN | SMMU_ACR_SMTNMB_TLBEN;
58 
59     if ((num_context > (SMMU->GR0.IDR1 & SMMU_IDR1_NUMCB)) ||
60         (num_context > (SMMU->GR0.IDR0 & SMMU_IDR0_NUMSMRG))) {
61         /* num_context too large */
62         return -1;
63     }
64 
65     /* Use all context banks for secure access */
66     temp = SMMU->GR0.SCR1;
67     temp &= ~(SMMU_SCR1_NSNUMCBO | SMMU_SCR1_NSNUMSMRGO);
68     SMMU->GR0.SCR1 = temp | (0 << SMMU_SCR1_NSNUMCBO_OFFSET) |
69         (0 << SMMU_SCR1_NSNUMSMRGO_OFFSET) | SMMU_SCR1_SPMEN;
70 
71     SMMU->GR0.CR0 =
72         (SMMU_CR0_SMCFCFG | SMMU_CR0_USFCFG | SMMU_CR0_STALLD |
73          SMMU_CR0_GCFGFIE | SMMU_CR0_GCFGFRE | SMMU_CR0_GFIE | SMMU_CR0_GFRE);
74 
75     for (i = 0; i < num_context; i++) {
76         SMMU->GR0.S2CR[i] = SMMU_S2CRn_TYPE_CONTEXT | i;
77         SMMU->GR0.SMR[i] = SMMU_SMRn_VALID |
78             (context_info[i].stream_match_mask << 16) |
79             context_info[i].stream_match_id;
80         SMMU_ns_cb_stage1_init(SMMU, i, context_info[i].base_addr, granule);
81     }
82 
83     SMMU_setup_PMU(SMMU);
84 
85     return 0;
86 }
87 
SMMU_ns_cb_stage1_init(MMU500_Type_t * SMMU,uint32_t cb,uint64_t base_addr,enum mmu500_granule granule)88 void SMMU_ns_cb_stage1_init(
89     MMU500_Type_t *SMMU,
90     uint32_t cb,
91     uint64_t base_addr,
92     enum mmu500_granule granule)
93 {
94     uint64_t temp;
95 
96     SMMU->GR1.CBAR[cb] = SMMU_CBAR_TYPE_STAGE1 | SMMU_CBAR_MEM_NORMAL;
97     SMMU->GR1.CBA2R[cb] = SMMU_CBA2R_VA64;
98 
99     SMMU->TCB[cb].CB_TCR =
100         (SMMU_TCR_EPD1 | SMMU_TCR_SH0_OUTER | SMMU_TCR_ORGN0_WBWA |
101          SMMU_TCR_IRGN0_WBWA | SMMU_TCR_T0SZ_256TB);
102 
103     switch (granule) {
104     case MMU500_GRANULE_4KB:
105         SMMU->TCB[cb].CB_TCR |= SMMU_TCR_TG0_4KB;
106         break;
107     case MMU500_GRANULE_16KB:
108         SMMU->TCB[cb].CB_TCR |= SMMU_TCR_TG0_16KB;
109         break;
110     case MMU500_GRANULE_64KB:
111         SMMU->TCB[cb].CB_TCR |= SMMU_TCR_TG0_64KB;
112         break;
113     }
114 
115     SMMU->TCB[cb].CB_TCR2 = SMMU_TCR2_SEP_47 | SMMU_TCR2_PASIZE_48;
116     SMMU->TCB[cb].CB_TTBR0 =
117         (((uint64_t)0) << SMMU_TTBRn_ASID_OFFSET) | ((uint64_t)base_addr);
118 
119     /*
120      * AttrIndx[2:0]: setting
121      *   2'b000: 0xFF=Outer write-back,non-transient normal memory,
122      *                read-write/Inner write-back.non-transient normal
123      * memory,read-write 2'b001: 0x00=Device-nGnRnE 2'b010-111: (not used)
124      */
125     temp = 0x00000000000000ffLLU;
126     SMMU->TCB[cb].CB_MAIR0 = (uint32_t)temp;
127     SMMU->TCB[cb].CB_MAIR1 = (uint32_t)(temp >> 32);
128 
129     SMMU->TCB[cb].CB_FSR = 0xffffffff;
130 
131     SMMU->TCB[cb].CB_SCTLR =
132         (SMMU_SCTLR_MEM_NORMAL | SMMU_SCTLR_UWXN | SMMU_SCTLR_CFIE |
133          SMMU_SCTLR_CFRE | SMMU_SCTLR_M);
134 }
135 
SMMU_s_disable(MMU500_Type_t * SMMU,uint32_t num_context)136 void SMMU_s_disable(MMU500_Type_t *SMMU, uint32_t num_context)
137 {
138     uint32_t i;
139 
140     if ((num_context > (SMMU->GR0.IDR1 & SMMU_IDR1_NUMCB)) ||
141         (num_context > (SMMU->GR0.IDR0 & SMMU_IDR0_NUMSMRG))) {
142         /* num_context too large */
143         return;
144     }
145 
146     SMMU->GR0.ACR &= ~(
147         SMMU_ACR_S2CRB_TLBEN | SMMU_ACR_MMUDISB_TLBEN | SMMU_ACR_SMTNMB_TLBEN);
148 
149     for (i = 0; i < num_context; i++)
150         SMMU->TCB[i].CB_SCTLR &= ~(SMMU_SCTLR_M);
151 }
152