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