123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /*
- * 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);
- }
- }
|