From 0bc4356deae7ff2de2441fc519f395e75bed8923 Mon Sep 17 00:00:00 2001 From: Bharat Kumar Reddy Gooty Date: Mon, 16 Dec 2019 09:09:43 -0800 Subject: [PATCH] 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 Signed-off-by: Vladimir Olovyannikov --- arch/arm/Kconfig | 10 +++ arch/arm/include/asm/gic-v3.h | 134 ++++++++++++++++++++++++++++++++++ arch/arm/lib/Makefile | 1 + arch/arm/lib/gic-v3-its.c | 100 +++++++++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 arch/arm/include/asm/gic-v3.h create mode 100644 arch/arm/lib/gic-v3-its.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 76365ef313..8f950778bd 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -61,6 +61,16 @@ config LNX_KRNL_IMG_TEXT_OFFSET_BASE endif endif +config GIC_V3_ITS + bool "ARM GICV3 ITS" + help + ARM GICV3 Interrupt translation service (ITS). + Basic support for programming locality specific peripheral + interrupts (LPI) configuration tables and enable LPI tables. + LPI configuration table can be used by u-boot or Linux. + ARM GICV3 has limitation, once the LPI table is enabled, LPI + configuration table can not be re-programmed, unless GICV3 reset. + config STATIC_RELA bool default y if ARM64 && !POSITION_INDEPENDENT diff --git a/arch/arm/include/asm/gic-v3.h b/arch/arm/include/asm/gic-v3.h new file mode 100644 index 0000000000..ac6c9e7013 --- /dev/null +++ b/arch/arm/include/asm/gic-v3.h @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2019 Broadcom. + */ + +#ifndef __GIC_V3_H__ +#define __GIC_V3_H__ + +#define GICR_CTLR_ENABLE_LPIS BIT(0) +#define GICR_CTLR_RWP BIT(3) + +#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) + +#define GICR_WAKER_PROCESSORSLEEP BIT(1) +#define GICR_WAKER_CHILDRENASLEEP BIT(2) + +#define GIC_BASER_CACHE_NCNB 0ULL +#define GIC_BASER_CACHE_SAMEASINNER 0ULL +#define GIC_BASER_CACHE_NC 1ULL +#define GIC_BASER_CACHE_RAWT 2ULL +#define GIC_BASER_CACHE_RAWB 3ULL +#define GIC_BASER_CACHE_WAWT 4ULL +#define GIC_BASER_CACHE_WAWB 5ULL +#define GIC_BASER_CACHE_RAWAWT 6ULL +#define GIC_BASER_CACHE_RAWAWB 7ULL +#define GIC_BASER_CACHE_MASK 7ULL +#define GIC_BASER_NONSHAREABLE 0ULL +#define GIC_BASER_INNERSHAREABLE 1ULL +#define GIC_BASER_OUTERSHAREABLE 2ULL +#define GIC_BASER_SHAREABILITY_MASK 3ULL + +#define GIC_BASER_CACHEABILITY(reg, inner_outer, type) \ + (GIC_BASER_CACHE_##type << reg##_##inner_outer##_CACHEABILITY_SHIFT) + +#define GIC_BASER_SHAREABILITY(reg, type) \ + (GIC_BASER_##type << reg##_SHAREABILITY_SHIFT) + +/* encode a size field of width @w containing @n - 1 units */ +#define GIC_ENCODE_SZ(n, w) (((unsigned long)(n) - 1) &\ + GENMASK_ULL(((w) - 1), 0)) + +#define GICR_PROPBASER_SHAREABILITY_SHIFT (10) +#define GICR_PROPBASER_INNER_CACHEABILITY_SHIFT (7) +#define GICR_PROPBASER_OUTER_CACHEABILITY_SHIFT (56) +#define GICR_PROPBASER_SHAREABILITY_MASK \ + GIC_BASER_SHAREABILITY(GICR_PROPBASER, SHAREABILITY_MASK) +#define GICR_PROPBASER_INNER_CACHEABILITY_MASK \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, MASK) +#define GICR_PROPBASER_OUTER_CACHEABILITY_MASK \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, OUTER, MASK) +#define GICR_PROPBASER_CACHEABILITY_MASK GICR_PROPBASER_INNER_CACHEABILITY_MASK + +#define GICR_PROPBASER_INNERSHAREABLE \ + GIC_BASER_SHAREABILITY(GICR_PROPBASER, INNERSHAREABLE) + +#define GICR_PROPBASER_NCNB \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, NCNB) +#define GICR_PROPBASER_NC \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, NC) +#define GICR_PROPBASER_RAWT \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RAWT) +#define GICR_PROPBASER_RAWB \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RAWB) +#define GICR_PROPBASER_WAWT \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, WAWT) +#define GICR_PROPBASER_WAWB \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, WAWB) +#define GICR_PROPBASER_RAWAWT \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RAWAWT) +#define GICR_PROPBASER_RAWAWB \ + GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RAWAWB) + +#define GICR_PROPBASER_IDBITS_MASK (0x1f) +#define GICR_PROPBASER_ADDRESS(x) ((x) & GENMASK_ULL(51, 12)) +#define GICR_PENDBASER_ADDRESS(x) ((x) & GENMASK_ULL(51, 16)) + +#define GICR_PENDBASER_SHAREABILITY_SHIFT (10) +#define GICR_PENDBASER_INNER_CACHEABILITY_SHIFT (7) +#define GICR_PENDBASER_OUTER_CACHEABILITY_SHIFT (56) +#define GICR_PENDBASER_SHAREABILITY_MASK \ + GIC_BASER_SHAREABILITY(GICR_PENDBASER, SHAREABILITY_MASK) +#define GICR_PENDBASER_INNER_CACHEABILITY_MASK \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, MASK) +#define GICR_PENDBASER_OUTER_CACHEABILITY_MASK \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, OUTER, MASK) +#define GICR_PENDBASER_CACHEABILITY_MASK \ + GICR_PENDBASER_INNER_CACHEABILITY_MASK + +#define GICR_PENDBASER_INNERSHAREABLE \ + GIC_BASER_SHAREABILITY(GICR_PENDBASER, INNERSHAREABLE) + +#define GICR_PENDBASER_NCNB \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, NCNB) +#define GICR_PENDBASER_NC \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, NC) +#define GICR_PENDBASER_RAWT \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RAWT) +#define GICR_PENDBASER_RAWB \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RAWB) +#define GICR_PENDBASER_WAWT \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, WAWT) +#define GICR_PENDBASER_WAWB \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, WAWB) +#define GICR_PENDBASER_RAWAWT \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RAWAWT) +#define GICR_PENDBASER_RAWAWB \ + GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RAWAWB) + +#define GICR_PENDBASER_PTZ BIT_ULL(62) + +#define ITS_MAX_LPI_NRBITS 16 /* 64K LPIs */ + +#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1) +#define GICD_TYPER_NUM_LPIS(typer) ((((typer) >> 11) & 0x1f) + 1) +#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) + +/* Message based interrupts support */ +#define GICD_TYPER_MBIS BIT(16) +/* LPI support */ +#define GICD_TYPER_LPIS BIT(17) +#define GICD_TYPER_RSS BIT(26) + +#define GIC_REDISTRIBUTOR_OFFSET 0x20000 + +#ifdef CONFIG_GIC_V3_ITS +int gic_lpi_tables_init(u64 base, u32 max_redist); +#else +int gic_lpi_tables_init(u64 base, u32 max_redist) +{ + return 0; +} +#endif /* CONFIG_GIC_V3_ITS */ + +#endif /* __GIC_V3_H__ */ 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 +#include +#include +#include + +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; +} + -- 2.25.1