Varun Wadekar | eea6dc1 | 2021-05-04 16:14:09 -0700 | [diff] [blame] | 1 | /* |
Varun Wadekar | f6e7c95 | 2022-01-25 03:39:28 -0800 | [diff] [blame] | 2 | * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved. |
Varun Wadekar | eea6dc1 | 2021-05-04 16:14:09 -0700 | [diff] [blame] | 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 | { |
anzhou | 31cf318 | 2021-11-18 19:18:13 +0800 | [diff] [blame] | 49 | uint32_t timeout_count = GICFMU_IDLE_TIMEOUT_US; |
Varun Wadekar | eea6dc1 | 2021-05-04 16:14:09 -0700 | [diff] [blame] | 50 | uint64_t status; |
| 51 | |
| 52 | /* wait until status is 'busy' */ |
| 53 | do { |
| 54 | status = (gic_fmu_read_status(base) & BIT(0)); |
| 55 | |
anzhou | 31cf318 | 2021-11-18 19:18:13 +0800 | [diff] [blame] | 56 | if (timeout_count-- == 0U) { |
Varun Wadekar | eea6dc1 | 2021-05-04 16:14:09 -0700 | [diff] [blame] | 57 | ERROR("GIC600 AE FMU is not responding\n"); |
| 58 | panic(); |
| 59 | } |
anzhou | 31cf318 | 2021-11-18 19:18:13 +0800 | [diff] [blame] | 60 | |
| 61 | udelay(1U); |
| 62 | |
Varun Wadekar | eea6dc1 | 2021-05-04 16:14:09 -0700 | [diff] [blame] | 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 | } |
Varun Wadekar | f6e7c95 | 2022-01-25 03:39:28 -0800 | [diff] [blame] | 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 | } |