From 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 11:13:47 +0200 Subject: Adding upstream version 2.8.0+dfsg. Signed-off-by: Daniel Baumann --- drivers/arm/gic/v3/gic600ae_fmu_helpers.c | 304 ++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 drivers/arm/gic/v3/gic600ae_fmu_helpers.c (limited to 'drivers/arm/gic/v3/gic600ae_fmu_helpers.c') diff --git a/drivers/arm/gic/v3/gic600ae_fmu_helpers.c b/drivers/arm/gic/v3/gic600ae_fmu_helpers.c new file mode 100644 index 0000000..09806dc --- /dev/null +++ b/drivers/arm/gic/v3/gic600ae_fmu_helpers.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include + +#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); + } +} -- cgit v1.2.3