1 /* 2 * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 10 #include <arch.h> 11 #include <arch_helpers.h> 12 #include <drivers/arm/gic600ae_fmu.h> 13 #include <drivers/delay_timer.h> 14 #include <lib/mmio.h> 15 16 #define GICFMU_IDLE_TIMEOUT_US U(2000000) 17 18 /* Macro to write 32-bit FMU registers */ 19 #define GIC_FMU_WRITE_32(base, reg, val) \ 20 do { \ 21 /* \ 22 * This register receives the unlock key that is required for \ 23 * writes to FMU registers to be successful. \ 24 */ \ 25 mmio_write_32(base + GICFMU_KEY, 0xBE); \ 26 /* Perform the actual write */ \ 27 mmio_write_32((base) + (reg), (val)); \ 28 } while (false) 29 30 /* Macro to write 64-bit FMU registers */ 31 #define GIC_FMU_WRITE_64(base, reg, n, val) \ 32 do { \ 33 /* \ 34 * This register receives the unlock key that is required for \ 35 * writes to FMU registers to be successful. \ 36 */ \ 37 mmio_write_32(base + GICFMU_KEY, 0xBE); \ 38 /* \ 39 * APB bus is 32-bit wide; so split the 64-bit write into \ 40 * two 32-bit writes \ 41 */ \ 42 mmio_write_32((base) + reg##_LO + (n * 64), (val)); \ 43 mmio_write_32((base) + reg##_HI + (n * 64), (val)); \ 44 } while (false) 45 46 /* Helper function to wait until FMU is ready to accept the next command */ 47 static void wait_until_fmu_is_idle(uintptr_t base) 48 { 49 uint32_t timeout_count = GICFMU_IDLE_TIMEOUT_US; 50 uint64_t status; 51 52 /* wait until status is 'busy' */ 53 do { 54 status = (gic_fmu_read_status(base) & BIT(0)); 55 56 if (timeout_count-- == 0U) { 57 ERROR("GIC600 AE FMU is not responding\n"); 58 panic(); 59 } 60 61 udelay(1U); 62 63 } while (status == U(0)); 64 } 65 66 #define GIC_FMU_WRITE_ON_IDLE_32(base, reg, val) \ 67 do { \ 68 /* Wait until FMU is ready */ \ 69 wait_until_fmu_is_idle(base); \ 70 /* Actual register write */ \ 71 GIC_FMU_WRITE_32(base, reg, val); \ 72 /* Wait until FMU is ready */ \ 73 wait_until_fmu_is_idle(base); \ 74 } while (false) 75 76 #define GIC_FMU_WRITE_ON_IDLE_64(base, reg, n, val) \ 77 do { \ 78 /* Wait until FMU is ready */ \ 79 wait_until_fmu_is_idle(base); \ 80 /* Actual register write */ \ 81 GIC_FMU_WRITE_64(base, reg, n, val); \ 82 /* Wait until FMU is ready */ \ 83 wait_until_fmu_is_idle(base); \ 84 } while (false) 85 86 /******************************************************************************* 87 * GIC FMU functions for accessing the Fault Management Unit registers 88 ******************************************************************************/ 89 90 /* 91 * Accessors to read the Error Record Feature Register bits corresponding 92 * to an error record 'n' 93 */ 94 uint64_t gic_fmu_read_errfr(uintptr_t base, unsigned int n) 95 { 96 /* 97 * APB bus is 32-bit wide; so split the 64-bit read into 98 * two 32-bit reads 99 */ 100 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRFR_LO + n * 64U); 101 102 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRFR_HI + n * 64U) << 32); 103 return reg_val; 104 } 105 106 /* 107 * Accessors to read the Error Record Control Register bits corresponding 108 * to an error record 'n' 109 */ 110 uint64_t gic_fmu_read_errctlr(uintptr_t base, unsigned int n) 111 { 112 /* 113 * APB bus is 32-bit wide; so split the 64-bit read into 114 * two 32-bit reads 115 */ 116 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_LO + n * 64U); 117 118 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_HI + n * 64U) << 32); 119 return reg_val; 120 } 121 122 /* 123 * Accessors to read the Error Record Primary Status Register bits 124 * corresponding to an error record 'n' 125 */ 126 uint64_t gic_fmu_read_errstatus(uintptr_t base, unsigned int n) 127 { 128 /* 129 * APB bus is 32-bit wide; so split the 64-bit read into 130 * two 32-bit reads 131 */ 132 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_LO + n * 64U); 133 134 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_HI + n * 64U) << 32); 135 return reg_val; 136 } 137 138 /* 139 * Accessors to read the Error Group Status Register 140 */ 141 uint64_t gic_fmu_read_errgsr(uintptr_t base) 142 { 143 /* 144 * APB bus is 32-bit wide; so split the 64-bit read into 145 * two 32-bit reads 146 */ 147 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRGSR_LO); 148 149 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRGSR_HI) << 32); 150 return reg_val; 151 } 152 153 /* 154 * Accessors to read the Ping Control Register 155 */ 156 uint32_t gic_fmu_read_pingctlr(uintptr_t base) 157 { 158 return mmio_read_32(base + GICFMU_PINGCTLR); 159 } 160 161 /* 162 * Accessors to read the Ping Now Register 163 */ 164 uint32_t gic_fmu_read_pingnow(uintptr_t base) 165 { 166 return mmio_read_32(base + GICFMU_PINGNOW); 167 } 168 169 /* 170 * Accessors to read the Ping Mask Register 171 */ 172 uint64_t gic_fmu_read_pingmask(uintptr_t base) 173 { 174 /* 175 * APB bus is 32-bit wide; so split the 64-bit read into 176 * two 32-bit reads 177 */ 178 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_PINGMASK_LO); 179 180 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_PINGMASK_HI) << 32); 181 return reg_val; 182 } 183 184 /* 185 * Accessors to read the FMU Status Register 186 */ 187 uint32_t gic_fmu_read_status(uintptr_t base) 188 { 189 return mmio_read_32(base + GICFMU_STATUS); 190 } 191 192 /* 193 * Accessors to read the Error Record ID Register 194 */ 195 uint32_t gic_fmu_read_erridr(uintptr_t base) 196 { 197 return mmio_read_32(base + GICFMU_ERRIDR); 198 } 199 200 /* 201 * Accessors to write a 64 bit value to the Error Record Control Register 202 */ 203 void gic_fmu_write_errctlr(uintptr_t base, unsigned int n, uint64_t val) 204 { 205 GIC_FMU_WRITE_64(base, GICFMU_ERRCTLR, n, val); 206 } 207 208 /* 209 * Accessors to write a 64 bit value to the Error Record Primary Status 210 * Register 211 */ 212 void gic_fmu_write_errstatus(uintptr_t base, unsigned int n, uint64_t val) 213 { 214 /* Wait until FMU is ready before writing */ 215 GIC_FMU_WRITE_ON_IDLE_64(base, GICFMU_ERRSTATUS, n, val); 216 } 217 218 /* 219 * Accessors to write a 32 bit value to the Ping Control Register 220 */ 221 void gic_fmu_write_pingctlr(uintptr_t base, uint32_t val) 222 { 223 GIC_FMU_WRITE_32(base, GICFMU_PINGCTLR, val); 224 } 225 226 /* 227 * Accessors to write a 32 bit value to the Ping Now Register 228 */ 229 void gic_fmu_write_pingnow(uintptr_t base, uint32_t val) 230 { 231 /* Wait until FMU is ready before writing */ 232 GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_PINGNOW, val); 233 } 234 235 /* 236 * Accessors to write a 32 bit value to the Safety Mechanism Enable Register 237 */ 238 void gic_fmu_write_smen(uintptr_t base, uint32_t val) 239 { 240 /* Wait until FMU is ready before writing */ 241 GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMEN, val); 242 } 243 244 /* 245 * Accessors to write a 32 bit value to the Safety Mechanism Inject Error 246 * Register 247 */ 248 void gic_fmu_write_sminjerr(uintptr_t base, uint32_t val) 249 { 250 /* Wait until FMU is ready before writing */ 251 GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMINJERR, val); 252 } 253 254 /* 255 * Accessors to write a 64 bit value to the Ping Mask Register 256 */ 257 void gic_fmu_write_pingmask(uintptr_t base, uint64_t val) 258 { 259 GIC_FMU_WRITE_64(base, GICFMU_PINGMASK, 0, val); 260 } 261 262 /* 263 * Helper function to disable all safety mechanisms for a given block 264 */ 265 void gic_fmu_disable_all_sm_blkid(uintptr_t base, unsigned int blkid) 266 { 267 uint32_t smen, max_smid = U(0); 268 269 /* Sanity check block ID */ 270 assert((blkid >= FMU_BLK_GICD) && (blkid <= FMU_BLK_PPI31)); 271 272 /* Find the max safety mechanism ID for the block */ 273 switch (blkid) { 274 case FMU_BLK_GICD: 275 max_smid = FMU_SMID_GICD_MAX; 276 break; 277 278 case FMU_BLK_SPICOL: 279 max_smid = FMU_SMID_SPICOL_MAX; 280 break; 281 282 case FMU_BLK_WAKERQ: 283 max_smid = FMU_SMID_WAKERQ_MAX; 284 break; 285 286 case FMU_BLK_ITS0...FMU_BLK_ITS7: 287 max_smid = FMU_SMID_ITS_MAX; 288 break; 289 290 case FMU_BLK_PPI0...FMU_BLK_PPI31: 291 max_smid = FMU_SMID_PPI_MAX; 292 break; 293 294 default: 295 assert(false); 296 break; 297 } 298 299 /* Disable all Safety Mechanisms for a given block id */ 300 for (unsigned int i = 0U; i < max_smid; i++) { 301 smen = (blkid << FMU_SMEN_BLK_SHIFT) | (i << FMU_SMEN_SMID_SHIFT); 302 gic_fmu_write_smen(base, smen); 303 } 304 } 305