1 /* 2 * Copyright (c) 2021, 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 uint64_t timeout_ref = timeout_init_us(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_elapsed(timeout_ref)) { 57 ERROR("GIC600 AE FMU is not responding\n"); 58 panic(); 59 } 60 } while (status == U(0)); 61 } 62 63 #define GIC_FMU_WRITE_ON_IDLE_32(base, reg, val) \ 64 do { \ 65 /* Wait until FMU is ready */ \ 66 wait_until_fmu_is_idle(base); \ 67 /* Actual register write */ \ 68 GIC_FMU_WRITE_32(base, reg, val); \ 69 /* Wait until FMU is ready */ \ 70 wait_until_fmu_is_idle(base); \ 71 } while (false) 72 73 #define GIC_FMU_WRITE_ON_IDLE_64(base, reg, n, val) \ 74 do { \ 75 /* Wait until FMU is ready */ \ 76 wait_until_fmu_is_idle(base); \ 77 /* Actual register write */ \ 78 GIC_FMU_WRITE_64(base, reg, n, val); \ 79 /* Wait until FMU is ready */ \ 80 wait_until_fmu_is_idle(base); \ 81 } while (false) 82 83 /******************************************************************************* 84 * GIC FMU functions for accessing the Fault Management Unit registers 85 ******************************************************************************/ 86 87 /* 88 * Accessors to read the Error Record Feature Register bits corresponding 89 * to an error record 'n' 90 */ 91 uint64_t gic_fmu_read_errfr(uintptr_t base, unsigned int n) 92 { 93 /* 94 * APB bus is 32-bit wide; so split the 64-bit read into 95 * two 32-bit reads 96 */ 97 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRFR_LO + n * 64U); 98 99 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRFR_HI + n * 64U) << 32); 100 return reg_val; 101 } 102 103 /* 104 * Accessors to read the Error Record Control Register bits corresponding 105 * to an error record 'n' 106 */ 107 uint64_t gic_fmu_read_errctlr(uintptr_t base, unsigned int n) 108 { 109 /* 110 * APB bus is 32-bit wide; so split the 64-bit read into 111 * two 32-bit reads 112 */ 113 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_LO + n * 64U); 114 115 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_HI + n * 64U) << 32); 116 return reg_val; 117 } 118 119 /* 120 * Accessors to read the Error Record Primary Status Register bits 121 * corresponding to an error record 'n' 122 */ 123 uint64_t gic_fmu_read_errstatus(uintptr_t base, unsigned int n) 124 { 125 /* 126 * APB bus is 32-bit wide; so split the 64-bit read into 127 * two 32-bit reads 128 */ 129 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_LO + n * 64U); 130 131 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_HI + n * 64U) << 32); 132 return reg_val; 133 } 134 135 /* 136 * Accessors to read the Error Group Status Register 137 */ 138 uint64_t gic_fmu_read_errgsr(uintptr_t base) 139 { 140 /* 141 * APB bus is 32-bit wide; so split the 64-bit read into 142 * two 32-bit reads 143 */ 144 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRGSR_LO); 145 146 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRGSR_HI) << 32); 147 return reg_val; 148 } 149 150 /* 151 * Accessors to read the Ping Control Register 152 */ 153 uint32_t gic_fmu_read_pingctlr(uintptr_t base) 154 { 155 return mmio_read_32(base + GICFMU_PINGCTLR); 156 } 157 158 /* 159 * Accessors to read the Ping Now Register 160 */ 161 uint32_t gic_fmu_read_pingnow(uintptr_t base) 162 { 163 return mmio_read_32(base + GICFMU_PINGNOW); 164 } 165 166 /* 167 * Accessors to read the Ping Mask Register 168 */ 169 uint64_t gic_fmu_read_pingmask(uintptr_t base) 170 { 171 /* 172 * APB bus is 32-bit wide; so split the 64-bit read into 173 * two 32-bit reads 174 */ 175 uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_PINGMASK_LO); 176 177 reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_PINGMASK_HI) << 32); 178 return reg_val; 179 } 180 181 /* 182 * Accessors to read the FMU Status Register 183 */ 184 uint32_t gic_fmu_read_status(uintptr_t base) 185 { 186 return mmio_read_32(base + GICFMU_STATUS); 187 } 188 189 /* 190 * Accessors to read the Error Record ID Register 191 */ 192 uint32_t gic_fmu_read_erridr(uintptr_t base) 193 { 194 return mmio_read_32(base + GICFMU_ERRIDR); 195 } 196 197 /* 198 * Accessors to write a 64 bit value to the Error Record Control Register 199 */ 200 void gic_fmu_write_errctlr(uintptr_t base, unsigned int n, uint64_t val) 201 { 202 GIC_FMU_WRITE_64(base, GICFMU_ERRCTLR, n, val); 203 } 204 205 /* 206 * Accessors to write a 64 bit value to the Error Record Primary Status 207 * Register 208 */ 209 void gic_fmu_write_errstatus(uintptr_t base, unsigned int n, uint64_t val) 210 { 211 /* Wait until FMU is ready before writing */ 212 GIC_FMU_WRITE_ON_IDLE_64(base, GICFMU_ERRSTATUS, n, val); 213 } 214 215 /* 216 * Accessors to write a 32 bit value to the Ping Control Register 217 */ 218 void gic_fmu_write_pingctlr(uintptr_t base, uint32_t val) 219 { 220 GIC_FMU_WRITE_32(base, GICFMU_PINGCTLR, val); 221 } 222 223 /* 224 * Accessors to write a 32 bit value to the Ping Now Register 225 */ 226 void gic_fmu_write_pingnow(uintptr_t base, uint32_t val) 227 { 228 /* Wait until FMU is ready before writing */ 229 GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_PINGNOW, val); 230 } 231 232 /* 233 * Accessors to write a 32 bit value to the Safety Mechanism Enable Register 234 */ 235 void gic_fmu_write_smen(uintptr_t base, uint32_t val) 236 { 237 /* Wait until FMU is ready before writing */ 238 GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMEN, val); 239 } 240 241 /* 242 * Accessors to write a 32 bit value to the Safety Mechanism Inject Error 243 * Register 244 */ 245 void gic_fmu_write_sminjerr(uintptr_t base, uint32_t val) 246 { 247 /* Wait until FMU is ready before writing */ 248 GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMINJERR, val); 249 } 250 251 /* 252 * Accessors to write a 64 bit value to the Ping Mask Register 253 */ 254 void gic_fmu_write_pingmask(uintptr_t base, uint64_t val) 255 { 256 GIC_FMU_WRITE_64(base, GICFMU_PINGMASK, 0, val); 257 } 258