mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-19 02:54:24 +00:00

This patch updates the gic600_fmu_init function to disable all safety mechanisms for a block ID that is not present on the platform. All safety mechanisms for GIC-600AE are enabled by default and should be disabled for blocks that are not present on the platform to avoid false positive RAS errors. Change-Id: I52dc3bee9a8b49fd2e51d7ed851fdc803a48e6e3 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
304 lines
7.4 KiB
C
304 lines
7.4 KiB
C
/*
|
|
* Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
|
|
#include <arch.h>
|
|
#include <arch_helpers.h>
|
|
#include <drivers/arm/gic600ae_fmu.h>
|
|
#include <drivers/delay_timer.h>
|
|
#include <lib/mmio.h>
|
|
|
|
#define GICFMU_IDLE_TIMEOUT_US U(2000000)
|
|
|
|
/* Macro to write 32-bit FMU registers */
|
|
#define GIC_FMU_WRITE_32(base, reg, val) \
|
|
do { \
|
|
/* \
|
|
* This register receives the unlock key that is required for \
|
|
* writes to FMU registers to be successful. \
|
|
*/ \
|
|
mmio_write_32(base + GICFMU_KEY, 0xBE); \
|
|
/* Perform the actual write */ \
|
|
mmio_write_32((base) + (reg), (val)); \
|
|
} while (false)
|
|
|
|
/* Macro to write 64-bit FMU registers */
|
|
#define GIC_FMU_WRITE_64(base, reg, n, val) \
|
|
do { \
|
|
/* \
|
|
* This register receives the unlock key that is required for \
|
|
* writes to FMU registers to be successful. \
|
|
*/ \
|
|
mmio_write_32(base + GICFMU_KEY, 0xBE); \
|
|
/* \
|
|
* APB bus is 32-bit wide; so split the 64-bit write into \
|
|
* two 32-bit writes \
|
|
*/ \
|
|
mmio_write_32((base) + reg##_LO + (n * 64), (val)); \
|
|
mmio_write_32((base) + reg##_HI + (n * 64), (val)); \
|
|
} while (false)
|
|
|
|
/* Helper function to wait until FMU is ready to accept the next command */
|
|
static void wait_until_fmu_is_idle(uintptr_t base)
|
|
{
|
|
uint32_t timeout_count = GICFMU_IDLE_TIMEOUT_US;
|
|
uint64_t status;
|
|
|
|
/* wait until status is 'busy' */
|
|
do {
|
|
status = (gic_fmu_read_status(base) & BIT(0));
|
|
|
|
if (timeout_count-- == 0U) {
|
|
ERROR("GIC600 AE FMU is not responding\n");
|
|
panic();
|
|
}
|
|
|
|
udelay(1U);
|
|
|
|
} while (status == U(0));
|
|
}
|
|
|
|
#define GIC_FMU_WRITE_ON_IDLE_32(base, reg, val) \
|
|
do { \
|
|
/* Wait until FMU is ready */ \
|
|
wait_until_fmu_is_idle(base); \
|
|
/* Actual register write */ \
|
|
GIC_FMU_WRITE_32(base, reg, val); \
|
|
/* Wait until FMU is ready */ \
|
|
wait_until_fmu_is_idle(base); \
|
|
} while (false)
|
|
|
|
#define GIC_FMU_WRITE_ON_IDLE_64(base, reg, n, val) \
|
|
do { \
|
|
/* Wait until FMU is ready */ \
|
|
wait_until_fmu_is_idle(base); \
|
|
/* Actual register write */ \
|
|
GIC_FMU_WRITE_64(base, reg, n, val); \
|
|
/* Wait until FMU is ready */ \
|
|
wait_until_fmu_is_idle(base); \
|
|
} while (false)
|
|
|
|
/*******************************************************************************
|
|
* GIC FMU functions for accessing the Fault Management Unit registers
|
|
******************************************************************************/
|
|
|
|
/*
|
|
* Accessors to read the Error Record Feature Register bits corresponding
|
|
* to an error record 'n'
|
|
*/
|
|
uint64_t gic_fmu_read_errfr(uintptr_t base, unsigned int n)
|
|
{
|
|
/*
|
|
* APB bus is 32-bit wide; so split the 64-bit read into
|
|
* two 32-bit reads
|
|
*/
|
|
uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRFR_LO + n * 64U);
|
|
|
|
reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRFR_HI + n * 64U) << 32);
|
|
return reg_val;
|
|
}
|
|
|
|
/*
|
|
* Accessors to read the Error Record Control Register bits corresponding
|
|
* to an error record 'n'
|
|
*/
|
|
uint64_t gic_fmu_read_errctlr(uintptr_t base, unsigned int n)
|
|
{
|
|
/*
|
|
* APB bus is 32-bit wide; so split the 64-bit read into
|
|
* two 32-bit reads
|
|
*/
|
|
uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_LO + n * 64U);
|
|
|
|
reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_HI + n * 64U) << 32);
|
|
return reg_val;
|
|
}
|
|
|
|
/*
|
|
* Accessors to read the Error Record Primary Status Register bits
|
|
* corresponding to an error record 'n'
|
|
*/
|
|
uint64_t gic_fmu_read_errstatus(uintptr_t base, unsigned int n)
|
|
{
|
|
/*
|
|
* APB bus is 32-bit wide; so split the 64-bit read into
|
|
* two 32-bit reads
|
|
*/
|
|
uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_LO + n * 64U);
|
|
|
|
reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_HI + n * 64U) << 32);
|
|
return reg_val;
|
|
}
|
|
|
|
/*
|
|
* Accessors to read the Error Group Status Register
|
|
*/
|
|
uint64_t gic_fmu_read_errgsr(uintptr_t base)
|
|
{
|
|
/*
|
|
* APB bus is 32-bit wide; so split the 64-bit read into
|
|
* two 32-bit reads
|
|
*/
|
|
uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRGSR_LO);
|
|
|
|
reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRGSR_HI) << 32);
|
|
return reg_val;
|
|
}
|
|
|
|
/*
|
|
* Accessors to read the Ping Control Register
|
|
*/
|
|
uint32_t gic_fmu_read_pingctlr(uintptr_t base)
|
|
{
|
|
return mmio_read_32(base + GICFMU_PINGCTLR);
|
|
}
|
|
|
|
/*
|
|
* Accessors to read the Ping Now Register
|
|
*/
|
|
uint32_t gic_fmu_read_pingnow(uintptr_t base)
|
|
{
|
|
return mmio_read_32(base + GICFMU_PINGNOW);
|
|
}
|
|
|
|
/*
|
|
* Accessors to read the Ping Mask Register
|
|
*/
|
|
uint64_t gic_fmu_read_pingmask(uintptr_t base)
|
|
{
|
|
/*
|
|
* APB bus is 32-bit wide; so split the 64-bit read into
|
|
* two 32-bit reads
|
|
*/
|
|
uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_PINGMASK_LO);
|
|
|
|
reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_PINGMASK_HI) << 32);
|
|
return reg_val;
|
|
}
|
|
|
|
/*
|
|
* Accessors to read the FMU Status Register
|
|
*/
|
|
uint32_t gic_fmu_read_status(uintptr_t base)
|
|
{
|
|
return mmio_read_32(base + GICFMU_STATUS);
|
|
}
|
|
|
|
/*
|
|
* Accessors to read the Error Record ID Register
|
|
*/
|
|
uint32_t gic_fmu_read_erridr(uintptr_t base)
|
|
{
|
|
return mmio_read_32(base + GICFMU_ERRIDR);
|
|
}
|
|
|
|
/*
|
|
* Accessors to write a 64 bit value to the Error Record Control Register
|
|
*/
|
|
void gic_fmu_write_errctlr(uintptr_t base, unsigned int n, uint64_t val)
|
|
{
|
|
GIC_FMU_WRITE_64(base, GICFMU_ERRCTLR, n, val);
|
|
}
|
|
|
|
/*
|
|
* Accessors to write a 64 bit value to the Error Record Primary Status
|
|
* Register
|
|
*/
|
|
void gic_fmu_write_errstatus(uintptr_t base, unsigned int n, uint64_t val)
|
|
{
|
|
/* Wait until FMU is ready before writing */
|
|
GIC_FMU_WRITE_ON_IDLE_64(base, GICFMU_ERRSTATUS, n, val);
|
|
}
|
|
|
|
/*
|
|
* Accessors to write a 32 bit value to the Ping Control Register
|
|
*/
|
|
void gic_fmu_write_pingctlr(uintptr_t base, uint32_t val)
|
|
{
|
|
GIC_FMU_WRITE_32(base, GICFMU_PINGCTLR, val);
|
|
}
|
|
|
|
/*
|
|
* Accessors to write a 32 bit value to the Ping Now Register
|
|
*/
|
|
void gic_fmu_write_pingnow(uintptr_t base, uint32_t val)
|
|
{
|
|
/* Wait until FMU is ready before writing */
|
|
GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_PINGNOW, val);
|
|
}
|
|
|
|
/*
|
|
* Accessors to write a 32 bit value to the Safety Mechanism Enable Register
|
|
*/
|
|
void gic_fmu_write_smen(uintptr_t base, uint32_t val)
|
|
{
|
|
/* Wait until FMU is ready before writing */
|
|
GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMEN, val);
|
|
}
|
|
|
|
/*
|
|
* Accessors to write a 32 bit value to the Safety Mechanism Inject Error
|
|
* Register
|
|
*/
|
|
void gic_fmu_write_sminjerr(uintptr_t base, uint32_t val)
|
|
{
|
|
/* Wait until FMU is ready before writing */
|
|
GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMINJERR, val);
|
|
}
|
|
|
|
/*
|
|
* Accessors to write a 64 bit value to the Ping Mask Register
|
|
*/
|
|
void gic_fmu_write_pingmask(uintptr_t base, uint64_t val)
|
|
{
|
|
GIC_FMU_WRITE_64(base, GICFMU_PINGMASK, 0, val);
|
|
}
|
|
|
|
/*
|
|
* Helper function to disable all safety mechanisms for a given block
|
|
*/
|
|
void gic_fmu_disable_all_sm_blkid(uintptr_t base, unsigned int blkid)
|
|
{
|
|
uint32_t smen, max_smid = U(0);
|
|
|
|
/* Sanity check block ID */
|
|
assert((blkid >= FMU_BLK_GICD) && (blkid <= FMU_BLK_PPI31));
|
|
|
|
/* Find the max safety mechanism ID for the block */
|
|
switch (blkid) {
|
|
case FMU_BLK_GICD:
|
|
max_smid = FMU_SMID_GICD_MAX;
|
|
break;
|
|
|
|
case FMU_BLK_SPICOL:
|
|
max_smid = FMU_SMID_SPICOL_MAX;
|
|
break;
|
|
|
|
case FMU_BLK_WAKERQ:
|
|
max_smid = FMU_SMID_WAKERQ_MAX;
|
|
break;
|
|
|
|
case FMU_BLK_ITS0...FMU_BLK_ITS7:
|
|
max_smid = FMU_SMID_ITS_MAX;
|
|
break;
|
|
|
|
case FMU_BLK_PPI0...FMU_BLK_PPI31:
|
|
max_smid = FMU_SMID_PPI_MAX;
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
/* Disable all Safety Mechanisms for a given block id */
|
|
for (unsigned int i = 0U; i < max_smid; i++) {
|
|
smen = (blkid << FMU_SMEN_BLK_SHIFT) | (i << FMU_SMEN_SMID_SHIFT);
|
|
gic_fmu_write_smen(base, smen);
|
|
}
|
|
}
|