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 67static volatile tk1_mc_regs_t *smmu_regs = (volatile tk1_mc_regs_t *)(SMMU_PPTR); 68 69static char smmu_pds[ARM_PLAT_NUM_SMMU][BIT(SMMU_PD_INDEX_BITS)] ALIGN(BIT(SMMU_PD_INDEX_BITS)); 70 71static void do_smmu_enable(void) 72{ 73 volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); 74 *config = 1; 75} 76 77static void do_smmu_disable(void) 78{ 79 volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); 80 *config = 0; 81} 82 83static 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 = addrFromPPtr(&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 102static inline void smmu_enable(void) 103{ 104 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) { 105 paddr_t addr = addrFromPPtr(&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 119static 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 137void plat_smmu_ptc_flush_all(void) 138{ 139 uint32_t cmd = PTC_FLUSH_ALL; 140 smmu_regs->smmu_ptc_flush = cmd; 141} 142 143void plat_smmu_tlb_flush_all(void) 144{ 145 uint32_t cmd = TLB_FLUSH_ALL; 146 smmu_regs->smmu_tlb_flush = cmd; 147} 148 149BOOT_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 216iopde_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 224void 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