From 913067d44f4daa2d58aacac0c33cb2938a0b3740 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Tue, 19 Aug 2014 15:34:51 -0500 Subject: [PATCH] tegra132: initialize GIC This provides are barebones initialization for tegra132 GIC on CPU0. It routes all interrupts to CPU0, moves them all into group 1, and attempts to allow non-secure access for all registers (doesn't appear to be implemented, though). BUG=chrome-os-partner:31449 BRANCH=None TEST=Built and booted past smp init in the kernel. Timers appear to be flowing now since jiffies are updated. Change-Id: Id45c13cc23e50feed3d88da13420c9eb694498a0 Signed-off-by: Patrick Georgi Original-Commit-Id: 81bad0a53083baa7af0f1fd5f82fef0538ee62df Original-Change-Id: I69dd9ae53f259e876a9bc4b9d7f65330150d2990 Original-Signed-off-by: Aaron Durbin Original-Reviewed-on: https://chromium-review.googlesource.com/212795 Original-Reviewed-by: Furquan Shaikh Reviewed-on: http://review.coreboot.org/8995 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/soc/nvidia/tegra132/Makefile.inc | 1 + src/soc/nvidia/tegra132/gic.c | 117 ++++++++++++++++++ .../nvidia/tegra132/include/soc/addressmap.h | 2 + .../nvidia/tegra132/include/soc/ramstage.h | 26 ++++ src/soc/nvidia/tegra132/soc.c | 2 + 5 files changed, 148 insertions(+) create mode 100644 src/soc/nvidia/tegra132/gic.c create mode 100644 src/soc/nvidia/tegra132/include/soc/ramstage.h diff --git a/src/soc/nvidia/tegra132/Makefile.inc b/src/soc/nvidia/tegra132/Makefile.inc index fb9b0334ac..b489d52afb 100644 --- a/src/soc/nvidia/tegra132/Makefile.inc +++ b/src/soc/nvidia/tegra132/Makefile.inc @@ -54,6 +54,7 @@ ramstage-y += soc.c ramstage-y += spi.c ramstage-y += i2c.c ramstage-y += dma.c +ramstage-y += gic.c ramstage-y += monotonic_timer.c ramstage-y += padconfig.c ramstage-y += funitcfg.c diff --git a/src/soc/nvidia/tegra132/gic.c b/src/soc/nvidia/tegra132/gic.c new file mode 100644 index 0000000000..95b592f799 --- /dev/null +++ b/src/soc/nvidia/tegra132/gic.c @@ -0,0 +1,117 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +enum { + GICD_CTLR = 0x0, + ENABLE_GRP0 = 0x1 << 0, + ENABLE_GRP1 = 0x1 << 1, + GICD_TYPER = 0x4, + GICD_ITARGETSR = 0x800, + GICD_IGROUPR = 0x80, + GICD_NSACR = 0xe00, + + GICC_CTLR = 0x0, + GICC_PMR = 0x4, +}; + +struct gicd { + uint32_t *base; + size_t num_interrupts; +}; + +static inline uint32_t gic_read(uint32_t *base, size_t byte_offset) +{ + return read32(&base[byte_offset / sizeof(uint32_t)]); +} + +static inline void gic_write(uint32_t *base, size_t byte_offset, uint32_t val) +{ + write32(val, &base[byte_offset / sizeof(uint32_t)]); +} + +static inline uint32_t gicd_read(struct gicd *gicd, size_t byte_offset) +{ + return gic_read(gicd->base, byte_offset); +} + +static inline void gicd_write(struct gicd *gicd, size_t byte_offset, + uint32_t val) +{ + gic_write(gicd->base, byte_offset, val); +} + +static void gic_write_regs(uint32_t *base, size_t offset, + size_t tot_interrupts, + size_t interrupts_per_reg, uint32_t val) +{ + size_t i; + size_t bound = sizeof(uint32_t) * tot_interrupts / interrupts_per_reg; + + for (i = 0; i < bound; i += sizeof(uint32_t)) + gic_write(base, offset + i, val); +} + +static void gicd_write_regs(struct gicd *gicd, size_t offset, + size_t interrupts_per_reg, uint32_t val) +{ + gic_write_regs(gicd->base, offset, gicd->num_interrupts, + interrupts_per_reg, val); +} + +static void gicd_init(struct gicd *gicd, uintptr_t base) +{ + uint32_t typer; + + gicd->base = (void *)base; + + typer = gicd_read(gicd, GICD_TYPER); + + gicd->num_interrupts = 32 * ((typer & 0x1f) + 1); + + printk(BIOS_DEBUG, "GICD at %p. TYPER=%08x, %zu interrupts.\n", + gicd->base, typer, gicd->num_interrupts); +} + +void gic_init(void) +{ + struct gicd gicd; + uint32_t * const gicc = (void *)(uintptr_t)TEGRA_GICC_BASE; + + gicd_init(&gicd, TEGRA_GICD_BASE); + + /* Enable Group 0 and Group 1 */ + gicd_write(&gicd, GICD_CTLR, ENABLE_GRP0 | ENABLE_GRP1); + + /* Enable Group 0 and Group 1 in GICC and enable all priroity levels. */ + gic_write(gicc, GICC_CTLR, ENABLE_GRP0 | ENABLE_GRP1); + gic_write(gicc, GICC_PMR, 1 << 7); + + /* All interrupts route go to CPU 0. */ + gicd_write_regs(&gicd, GICD_ITARGETSR, 4, 0x01010101); + /* Put all interrupts into Gropup 1. */ + gicd_write_regs(&gicd, GICD_IGROUPR, 32, 0xffffffff); + /* Allow Non-secure access to everything. */ + gicd_write_regs(&gicd, GICD_NSACR, 16, 0xffffffff); +} diff --git a/src/soc/nvidia/tegra132/include/soc/addressmap.h b/src/soc/nvidia/tegra132/include/soc/addressmap.h index 732c9e9366..ebe50f553e 100644 --- a/src/soc/nvidia/tegra132/include/soc/addressmap.h +++ b/src/soc/nvidia/tegra132/include/soc/addressmap.h @@ -31,6 +31,8 @@ enum { enum { TEGRA_ARM_PERIPHBASE = 0x50040000, + TEGRA_GICD_BASE = 0x50041000, + TEGRA_GICC_BASE = 0x50042000, TEGRA_ARM_DISPLAYA = 0x54200000, TEGRA_ARM_DISPLAYB = 0x54240000, TEGRA_ARM_SOR = 0x54540000, diff --git a/src/soc/nvidia/tegra132/include/soc/ramstage.h b/src/soc/nvidia/tegra132/include/soc/ramstage.h new file mode 100644 index 0000000000..e42f56d687 --- /dev/null +++ b/src/soc/nvidia/tegra132/include/soc/ramstage.h @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __SOC_NVIDIA_TEGRA132_SOC_RAMSTAGE_H__ +#define __SOC_NVIDIA_TEGRA132_SOC_RAMSTAGE_H__ + +void gic_init(void); + +#endif /* __SOC_NVIDIA_TEGRA132_SOC_RAMSTAGE_H__ */ + diff --git a/src/soc/nvidia/tegra132/soc.c b/src/soc/nvidia/tegra132/soc.c index 276ea7b784..13050f6c06 100644 --- a/src/soc/nvidia/tegra132/soc.c +++ b/src/soc/nvidia/tegra132/soc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include static void soc_read_resources(device_t dev) @@ -59,6 +60,7 @@ static void soc_init(device_t dev) { printk(BIOS_INFO, "CPU: Tegra132\n"); clock_init_arm_generic_timer(); + gic_init(); } static void soc_noop(device_t dev)