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