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>
This commit is contained in:
Bharat Kumar Reddy Gooty 2019-12-16 09:09:43 -08:00 committed by Tom Rini
parent 5819466dc1
commit 0bc4356dea
4 changed files with 245 additions and 0 deletions

View File

@ -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

View File

@ -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__ */

View File

@ -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

100
arch/arm/lib/gic-v3-its.c Normal file
View File

@ -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;
}