diff options
author | Bharat Kumar Reddy Gooty <bharat.gooty@broadcom.com> | 2019-12-16 09:09:43 -0800 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-01-10 14:18:26 -0500 |
commit | 0bc4356deae7ff2de2441fc519f395e75bed8923 (patch) | |
tree | 535d4de4b37f0adb3533e1f5fe1dfb66b2325cd1 /arch/arm/lib | |
parent | 5819466dc1d2856afa84188745eaa5f415ee08cb (diff) | |
download | u-boot-0bc4356deae7ff2de2441fc519f395e75bed8923.tar.gz |
arch: arm: Program GIC LPI configuration table
Programs the following:
1. Redistributor PROCBASER configuration table (which
is common for all redistributors)
2. Redistributor pending table (PENDBASER), for all the
available redistributors.
Signed-off-by: Bharat Kumar Reddy Gooty <bharat.gooty@broadcom.com>
Signed-off-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
Diffstat (limited to 'arch/arm/lib')
-rw-r--r-- | arch/arm/lib/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/lib/gic-v3-its.c | 100 |
2 files changed, 101 insertions, 0 deletions
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 9de9a9acee..8482f5446c 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_FSL_LAYERSCAPE) += ccn504.o ifneq ($(CONFIG_GICV2)$(CONFIG_GICV3),) obj-y += gic_64.o endif +obj-$(CONFIG_GIC_V3_ITS) += gic-v3-its.o obj-y += interrupts_64.o else obj-y += interrupts.o diff --git a/arch/arm/lib/gic-v3-its.c b/arch/arm/lib/gic-v3-its.c new file mode 100644 index 0000000000..e19ab01621 --- /dev/null +++ b/arch/arm/lib/gic-v3-its.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Broadcom. + */ +#include <common.h> +#include <asm/gic.h> +#include <asm/gic-v3.h> +#include <asm/io.h> + +static u32 lpi_id_bits; + +#define LPI_NRBITS lpi_id_bits +#define LPI_PROPBASE_SZ ALIGN(BIT(LPI_NRBITS), SZ_64K) +#define LPI_PENDBASE_SZ ALIGN(BIT(LPI_NRBITS) / 8, SZ_64K) + +/* + * Program the GIC LPI configuration tables for all + * the re-distributors and enable the LPI table + * base: Configuration table address + * num_redist: number of redistributors + */ +int gic_lpi_tables_init(u64 base, u32 num_redist) +{ + u32 gicd_typer; + u64 val; + u64 tmp; + int i; + u64 redist_lpi_base; + u64 pend_base = GICR_BASE + GICR_PENDBASER; + + gicd_typer = readl(GICD_BASE + GICD_TYPER); + + /* GIC support for Locality specific peripheral interrupts (LPI's) */ + if (!(gicd_typer & GICD_TYPER_LPIS)) { + pr_err("GIC implementation does not support LPI's\n"); + return -EINVAL; + } + + /* + * Check for LPI is disabled for all the redistributors. + * Once the LPI table is enabled, can not program the + * LPI configuration tables again, unless the GIC is reset. + */ + for (i = 0; i < num_redist; i++) { + u32 offset = i * GIC_REDISTRIBUTOR_OFFSET; + + if ((readl((uintptr_t)(GICR_BASE + offset))) & + GICR_CTLR_ENABLE_LPIS) { + pr_err("Re-Distributor %d LPI is already enabled\n", + i); + return -EINVAL; + } + } + + /* lpi_id_bits to get LPI_PENDBASE_SZ and LPi_PROPBASE_SZ */ + lpi_id_bits = min_t(u32, GICD_TYPER_ID_BITS(gicd_typer), + ITS_MAX_LPI_NRBITS); + + /* Set PropBase */ + val = (base | + GICR_PROPBASER_INNERSHAREABLE | + GICR_PROPBASER_RAWAWB | + ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK)); + + writeq(val, (GICR_BASE + GICR_PROPBASER)); + tmp = readl(GICR_BASE + GICR_PROPBASER); + if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { + if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) { + val &= ~(GICR_PROPBASER_SHAREABILITY_MASK | + GICR_PROPBASER_CACHEABILITY_MASK); + val |= GICR_PROPBASER_NC; + writeq(val, (GICR_BASE + GICR_PROPBASER)); + } + } + + redist_lpi_base = base + LPI_PROPBASE_SZ; + + for (i = 0; i < num_redist; i++) { + u32 offset = i * GIC_REDISTRIBUTOR_OFFSET; + + val = ((redist_lpi_base + (i * LPI_PENDBASE_SZ)) | + GICR_PENDBASER_INNERSHAREABLE | + GICR_PENDBASER_RAWAWB); + + writeq(val, (uintptr_t)(pend_base + offset)); + tmp = readq((uintptr_t)(pend_base + offset)); + if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { + val &= ~(GICR_PENDBASER_SHAREABILITY_MASK | + GICR_PENDBASER_CACHEABILITY_MASK); + val |= GICR_PENDBASER_NC; + writeq(val, (uintptr_t)(pend_base + offset)); + } + + /* Enable LPI for the redistributor */ + writel(GICR_CTLR_ENABLE_LPIS, (uintptr_t)(GICR_BASE + offset)); + } + + return 0; +} + |