1 /*
2 * Copyright 2016, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7 #include <types.h>
8 #include <config.h>
9
10 #ifdef CONFIG_TK1_SMMU
11
12 #include <plat/machine/smmu.h>
13 #include <linker.h>
14 #include <plat/machine/hardware.h>
15 #include <object/structures.h>
16
17
18 #define MC_PADDR 0x70019000
19 #define SMMU_CONFIG_OFFSET 0x10
20
21 #define PTB_DATA_BASE_SHIFT 12
22 #define PTB_DATA_READ BIT(31)
23 #define PTB_DATA_WRITE BIT(30)
24 #define PTB_DATA_NONSECURE BIT(29)
25 #define PTB_DATA_BASE_PD_MASK 0x3fffff
26
27 #define MODULE_ASID_ENABLE BIT(31)
28
29 #define PTC_FLUSH_ALL 0
30 #define PTC_FLUSH_ADR 1
31
32 #define TLB_ASID_MATCH BIT(31)
33 #define TLB_FLUSH_ALL (0)
34 #define TLB_FLUSH_SECTION (2)
35 #define TLB_FLUSH_GROUP (3)
36
37 #define MC_DECERR_MTS_BIT 16u
38 #define MC_SECERR_SEC_BIT 13u
39 #define MC_DECERR_VPR_BIT 12u
40 #define MC_APB_ASID_UPDATE_BIT 11u
41 #define MC_SMMU_PAGE_BIT 10u
42 #define MC_ARBITRATION_EMEM_BIT 9u
43 #define MC_SECURITY_BIT 8u
44 #define MC_DECERR_EMEM_BIT 6u
45
46
47 #define MC_ERR_ID_MASK 0x7f
48 #define MC_ERR_ADR_MASK 0x7000
49 #define MC_ERR_RW_MASK 0x10000
50 #define MC_ERR_SEC_MASK 0x20000
51 #define MC_ERR_SWAP_MASK 0x40000
52 #define MC_ERR_ADR_HI_MASK 0x300000
53 #define MC_ERR_INVALID_SMMU_PAGE_NONSECURE_MASK 0x2000000
54 #define MC_ERR_INVALID_SMMU_PAGE_WRITE_MASK 0x4000000
55 #define MC_ERR_INVALID_SMMU_PAGE_READ_MASK 0x8000000
56 #define MC_ERR_TYPE_MASK 0x70000000
57 #define MC_ERR_TYPE_SHIFT 28
58
59 #define MC_ERR_TYPE_RSVD 0
60 #define MC_ERR_TYPE_DECERR_EMEM 2
61 #define MC_ERR_TYPE_SECURITY 3
62 #define MC_ERR_TYPE_SECURITY_CARVEOUT 4
63 #define MC_ERR_TYPE_INVALID_SMMU_PAGE 6
64
65 #define IOPDE_4M_INDEX_SHIFT 22
66
67 static volatile tk1_mc_regs_t *smmu_regs = (volatile tk1_mc_regs_t *)(SMMU_PPTR);
68
69 static char smmu_pds[ARM_PLAT_NUM_SMMU][BIT(SMMU_PD_INDEX_BITS)] ALIGN(BIT(SMMU_PD_INDEX_BITS));
70
do_smmu_enable(void)71 static void do_smmu_enable(void)
72 {
73 volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET);
74 *config = 1;
75 }
76
do_smmu_disable(void)77 static void do_smmu_disable(void)
78 {
79 volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET);
80 *config = 0;
81 }
82
smmu_disable(void)83 static inline void smmu_disable(void)
84 {
85 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) {
86 /* in hyp mode, we need call the hook in monitor mode */
87 /* we need physical address here */
88 paddr_t addr = addrFromKPPtr(&do_smmu_disable);
89 asm(".arch_extension sec\n");
90 asm volatile("mov r0, %0\n\t"
91 "dsb\nisb\n"
92 "smc #0\n"
93 ::"r"(addr):"r0", "r1", "r2", "r3", "ip");
94 } else {
95 /* in secure mode, can enable it directly */
96 smmu_regs->smmu_config = 0;
97 }
98
99 return;
100 }
101
smmu_enable(void)102 static inline void smmu_enable(void)
103 {
104 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) {
105 paddr_t addr = addrFromKPPtr(&do_smmu_enable);
106 asm(".arch_extension sec\n");
107 asm volatile("mov r0, %0\n\t"
108 "dsb\nisb\n"
109 "smc #0\n"
110 ::"r"(addr):"r0", "r1", "r2", "r3", "ip");
111 } else {
112 smmu_regs->smmu_config = 1;
113 }
114
115 return;
116 }
117
118
make_ptb_data(uint32_t pd_base,bool_t read,bool_t write,bool_t nonsecure)119 static uint32_t make_ptb_data(uint32_t pd_base, bool_t read, bool_t write, bool_t nonsecure)
120 {
121 uint32_t ret = 0;
122 ret = (pd_base >> PTB_DATA_BASE_SHIFT);
123
124 if (read) {
125 ret |= PTB_DATA_READ;
126 }
127 if (write) {
128 ret |= PTB_DATA_WRITE;
129 }
130 if (nonsecure) {
131 ret |= PTB_DATA_NONSECURE;
132 }
133
134 return ret;
135 }
136
plat_smmu_ptc_flush_all(void)137 void plat_smmu_ptc_flush_all(void)
138 {
139 uint32_t cmd = PTC_FLUSH_ALL;
140 smmu_regs->smmu_ptc_flush = cmd;
141 }
142
plat_smmu_tlb_flush_all(void)143 void plat_smmu_tlb_flush_all(void)
144 {
145 uint32_t cmd = TLB_FLUSH_ALL;
146 smmu_regs->smmu_tlb_flush = cmd;
147 }
148
plat_smmu_init(void)149 BOOT_CODE int plat_smmu_init(void)
150 {
151 uint32_t asid;
152
153 smmu_disable();
154
155 for (asid = SMMU_FIRST_ASID; asid <= SMMU_LAST_ASID; asid++) {
156 iopde_t *pd = (iopde_t *) smmu_pds[asid - SMMU_FIRST_ASID];
157
158 memset(pd, 0, BIT(SMMU_PD_INDEX_BITS));
159 cleanCacheRange_RAM((word_t)pd, ((word_t)pd + BIT(SMMU_PD_INDEX_BITS)),
160 addrFromPPtr(pd));
161
162 smmu_regs->smmu_ptb_asid = asid;
163
164 /* make it read/write/nonsecure but all translation entries are invalid */
165 smmu_regs->smmu_ptb_data = make_ptb_data(pptr_to_paddr(pd), true, true, true);
166 }
167 printf("Total %d IOASID set up\n", (asid - 1));
168
169 /* now assign IOASID to each module */
170 smmu_regs->smmu_afi_asid = SMMU_AFI_ASID | MODULE_ASID_ENABLE;
171 smmu_regs->smmu_avpc_asid = SMMU_AVPC_ASID | MODULE_ASID_ENABLE;
172 smmu_regs->smmu_dc_asid = SMMU_DC_ASID | MODULE_ASID_ENABLE;
173 smmu_regs->smmu_dcb_asid = SMMU_DCB_ASID | MODULE_ASID_ENABLE;
174 smmu_regs->smmu_hc_asid = SMMU_HC_ASID | MODULE_ASID_ENABLE;
175 smmu_regs->smmu_hda_asid = SMMU_HDA_ASID | MODULE_ASID_ENABLE;
176 smmu_regs->smmu_isp2_asid = SMMU_ISP2_ASID | MODULE_ASID_ENABLE;
177 smmu_regs->smmu_msenc_asid = SMMU_MSENC_ASID | MODULE_ASID_ENABLE;
178 smmu_regs->smmu_nv_asid = SMMU_NV_ASID | MODULE_ASID_ENABLE;
179 smmu_regs->smmu_nv2_asid = SMMU_NV2_ASID | MODULE_ASID_ENABLE;
180 smmu_regs->smmu_ppcs_asid = SMMU_PPCS_ASID | MODULE_ASID_ENABLE;
181 smmu_regs->smmu_sata_asid = SMMU_SATA_ASID | MODULE_ASID_ENABLE;
182 smmu_regs->smmu_vde_asid = SMMU_VDE_ASID | MODULE_ASID_ENABLE;
183 smmu_regs->smmu_vi_asid = SMMU_VI_ASID | MODULE_ASID_ENABLE;
184 smmu_regs->smmu_vic_asid = SMMU_VIC_ASID | MODULE_ASID_ENABLE;
185 smmu_regs->smmu_xusb_host_asid = SMMU_XUSB_HOST_ASID | MODULE_ASID_ENABLE;
186 smmu_regs->smmu_xusb_dev_asid = SMMU_XUSB_DEV_ASID | MODULE_ASID_ENABLE;
187 smmu_regs->smmu_tsec_asid = SMMU_TSEC_ASID | MODULE_ASID_ENABLE;
188 smmu_regs->smmu_ppcs1_asid = SMMU_PPCS1_ASID | MODULE_ASID_ENABLE;
189 smmu_regs->smmu_sdmmc1a_asid = SMMU_SDMMC1A_ASID | MODULE_ASID_ENABLE;
190 smmu_regs->smmu_sdmmc2a_asid = SMMU_SDMMC2A_ASID | MODULE_ASID_ENABLE;
191 smmu_regs->smmu_sdmmc3a_asid = SMMU_SDMMC3A_ASID | MODULE_ASID_ENABLE;
192 smmu_regs->smmu_sdmmc4a_asid = SMMU_SDMMC4A_ASID | MODULE_ASID_ENABLE;
193 smmu_regs->smmu_isp2b_asid = SMMU_ISP2B_ASID | MODULE_ASID_ENABLE;
194 smmu_regs->smmu_gpu_asid = SMMU_GPU_ASID | MODULE_ASID_ENABLE;
195 smmu_regs->smmu_gpub_asid = SMMU_GPUB_ASID | MODULE_ASID_ENABLE;
196 smmu_regs->smmu_ppcs2_asid = SMMU_PPCS2_ASID | MODULE_ASID_ENABLE;
197
198 /* flush page table cache */
199 plat_smmu_ptc_flush_all();
200 /* flush TLB */
201 plat_smmu_tlb_flush_all();
202 smmu_enable();
203
204 /* also need to unmask interrupts */
205 if (config_set(CONFIG_SMMU_INTERRUPT_ENABLE)) {
206 smmu_regs->intmask = BIT(MC_APB_ASID_UPDATE_BIT) | BIT(MC_SMMU_PAGE_BIT) |
207 BIT(MC_DECERR_MTS_BIT) | BIT(MC_SECERR_SEC_BIT) |
208 BIT(MC_DECERR_VPR_BIT) | BIT(MC_ARBITRATION_EMEM_BIT) |
209 BIT(MC_SECURITY_BIT) | BIT(MC_DECERR_EMEM_BIT);
210 } else {
211 smmu_regs->intmask = 0;
212 }
213 return ARM_PLAT_NUM_SMMU;
214 }
215
plat_smmu_lookup_iopd_by_asid(uint32_t asid)216 iopde_t *plat_smmu_lookup_iopd_by_asid(uint32_t asid)
217 {
218 /* There should be no way to generate bad ASID values through the kernel
219 * so this is an assertion and not a check */
220 assert(asid >= SMMU_FIRST_ASID && asid <= SMMU_LAST_ASID);
221 return (iopde_t *) smmu_pds[asid - SMMU_FIRST_ASID];
222 }
223
plat_smmu_handle_interrupt(void)224 void plat_smmu_handle_interrupt(void)
225 {
226 uint32_t status = smmu_regs->intstatus;
227 uint32_t clear_status = 0;
228
229 if (status & BIT(MC_DECERR_MTS_BIT)) {
230 clear_status |= BIT(MC_DECERR_MTS_BIT);
231 }
232 if (status & BIT(MC_SECERR_SEC_BIT)) {
233 clear_status |= BIT(MC_SECERR_SEC_BIT);
234 }
235 if (status & BIT(MC_DECERR_VPR_BIT)) {
236 clear_status |= BIT(MC_DECERR_VPR_BIT);
237 }
238 if (status & BIT(MC_ARBITRATION_EMEM_BIT)) {
239 clear_status |= BIT(MC_ARBITRATION_EMEM_BIT);
240 }
241 if (status & BIT(MC_SECURITY_BIT)) {
242 clear_status |= BIT(MC_SECURITY_BIT);
243 }
244 if (status & BIT(MC_DECERR_EMEM_BIT)) {
245 clear_status |= BIT(MC_DECERR_EMEM_BIT);
246 }
247 if (status & BIT(MC_APB_ASID_UPDATE_BIT)) {
248 clear_status |= BIT(MC_APB_ASID_UPDATE_BIT);
249 }
250
251 /* we only care about SMMU translation failures */
252 if (status & BIT(MC_SMMU_PAGE_BIT)) {
253 if (config_set(CONFIG_PRINTING)) {
254 uint32_t err_status = smmu_regs->err_status;
255 uint32_t UNUSED err_adr = smmu_regs->err_adr;
256 uint32_t UNUSED id = err_status & MC_ERR_ID_MASK;
257 uint32_t UNUSED rw = (err_status & MC_ERR_RW_MASK);
258 uint32_t UNUSED read = (err_status & MC_ERR_INVALID_SMMU_PAGE_READ_MASK);
259 uint32_t UNUSED write = (err_status & MC_ERR_INVALID_SMMU_PAGE_WRITE_MASK);
260 uint32_t UNUSED nonsecure = (err_status & MC_ERR_INVALID_SMMU_PAGE_NONSECURE_MASK);
261 uint32_t UNUSED type = (err_status & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT;
262
263 printf("SMMU Address translation error:\n");
264 printf("ID: %d address: 0x%x type: %d direction: 0x%x\n", id, err_adr, type, rw);
265 printf("IOPT permission: read 0x%x write 0x%x nonsecure 0x%x\n", read, write, nonsecure);
266 }
267 clear_status |= BIT(MC_SMMU_PAGE_BIT);
268 }
269
270 /* write 1 to clear the interrupt */
271 smmu_regs->intstatus = clear_status;
272 }
273 #endif
274