Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for ARM Cortex-R #9316

Merged
merged 12 commits into from Aug 9, 2019
Next

interrupt_controller: gic: Add support for the GIC400

The GIC400 is a common interrupt controller that can be used with the
Cortex A and R series processors.  This patch adds basic interrupt
handling for the GIC, but does not handle multiple routing or
priorities.

Signed-off-by: Bradley Bolen <bbolen@lexmark.com>
  • Loading branch information...
Bradley Bolen
Bradley Bolen committed Apr 18, 2018
commit d1a7cefae819edff6d5fcef1c96341729f6e1352
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_sources_ifdef(CONFIG_ARCV2_INTERRUPT_UNIT arcv2_irq_unit.c)
zephyr_sources_ifdef(CONFIG_GIC gic-400.c)
zephyr_sources_ifdef(CONFIG_IOAPIC ioapic_intr.c)
zephyr_sources_ifdef(CONFIG_LOAPIC loapic_intr.c system_apic.c)
zephyr_sources_ifdef(CONFIG_LOAPIC_SPURIOUS_VECTOR loapic_spurious.S)
@@ -147,6 +147,13 @@ config DW_ICTL_INIT_PRIORITY
help
DesignWare Interrupt Controller initialization priority.

config GIC
bool "ARM Generic Interrupt Controller (GIC)"
depends on CPU_CORTEX_R
help
The ARM Generic Interrupt Controller works with Cortex-A and
Cortex-R processors.

source "drivers/interrupt_controller/Kconfig.stm32"

source "drivers/interrupt_controller/Kconfig.multilevel"
@@ -0,0 +1,246 @@
/*
* Copyright (c) 2018 Marvell
* Copyright (c) 2018 Lexmark International, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <device.h>
#include <sw_isr_table.h>
#include <irq_nextlevel.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>

#define DT_GIC_DIST_BASE DT_INST_0_ARM_GIC_BASE_ADDRESS_0
#define DT_GIC_CPU_BASE DT_INST_0_ARM_GIC_BASE_ADDRESS_1

#define GICD_CTRL (DT_GIC_DIST_BASE + 0)
#define GICD_TYPER (DT_GIC_DIST_BASE + 0x4)
#define GICD_IIDR (DT_GIC_DIST_BASE + 0x8)
#define GICD_IGROUPRn (DT_GIC_DIST_BASE + 0x80)
#define GICD_ISENABLERn (DT_GIC_DIST_BASE + 0x100)
#define GICD_ICENABLERn (DT_GIC_DIST_BASE + 0x180)
#define GICD_ISPENDRn (DT_GIC_DIST_BASE + 0x200)
#define GICD_ICPENDRn (DT_GIC_DIST_BASE + 0x280)
#define GICD_ISACTIVERn (DT_GIC_DIST_BASE + 0x300)
#define GICD_ICACTIVERn (DT_GIC_DIST_BASE + 0x380)
#define GICD_IPRIORITYRn (DT_GIC_DIST_BASE + 0x400)
#define GICD_ITARGETSRn (DT_GIC_DIST_BASE + 0x800)
#define GICD_ICFGRn (DT_GIC_DIST_BASE + 0xc00)
#define GICD_SGIR (DT_GIC_DIST_BASE + 0xf00)

#define GICC_CTRL (DT_GIC_CPU_BASE + 0x00)
#define GICC_PMR (DT_GIC_CPU_BASE + 0x04)
#define GICC_BPR (DT_GIC_CPU_BASE + 0x08)
#define GICC_IAR (DT_GIC_CPU_BASE + 0x0c)
#define GICC_EOIR (DT_GIC_CPU_BASE + 0x10)

#define GICC_ENABLE 3
#define GICC_DIS_BYPASS_MASK 0x1e0

#define NO_GIC_INT_PENDING 1023

#define GIC_SPI_INT_BASE 32

#define GIC_INT_TYPE_MASK 0x3
#define GIC_INT_TYPE_EDGE (1 << 1)

struct gic_ictl_config {
u32_t isr_table_offset;
};

static void gic_dist_init(void)
{
unsigned int gic_irqs, i;

gic_irqs = sys_read32(GICD_TYPER) & 0x1f;
gic_irqs = (gic_irqs + 1) * 32;
if (gic_irqs > 1020)
gic_irqs = 1020;

/*
* Disable the forwarding of pending interrupts
* from the Distributor to the CPU interfaces
*/
sys_write32(0, GICD_CTRL);

/*
* Set all global interrupts to this CPU only.
*/
for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4)
sys_write32(0x01010101, GICD_ITARGETSRn + i);

/*
* Set all global interrupts to be level triggered, active low.
*/
for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 16)
sys_write32(0, GICD_ICFGRn + i / 4);

/* Set priority on all global interrupts. */
for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4)
sys_write32(0, GICD_IPRIORITYRn + i);

/* Set all interrupts to group 0 */
for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32)
sys_write32(0, GICD_IGROUPRn + i / 8);

/*
* Disable all interrupts. Leave the PPI and SGIs alone
* as these enables are banked registers.
*/
for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) {
sys_write32(0xffffffff, GICD_ICACTIVERn + i / 8);
sys_write32(0xffffffff, GICD_ICENABLERn + i / 8);
}

/*
* Enable the forwarding of pending interrupts
* from the Distributor to the CPU interfaces
*/
sys_write32(1, GICD_CTRL);
}

static void gic_cpu_init(void)
{
int i;
u32_t val;

/*
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
sys_write32(0xffffffff, GICD_ICACTIVERn);
sys_write32(0xffff0000, GICD_ICENABLERn);
sys_write32(0x0000ffff, GICD_ISENABLERn);

/*
* Set priority on PPI and SGI interrupts
*/
for (i = 0; i < 32; i += 4)
sys_write32(0xa0a0a0a0, GICD_IPRIORITYRn + i);

sys_write32(0xf0, GICC_PMR);

/*
* Enable interrupts and signal them using the IRQ signal.
*/
val = sys_read32(GICC_CTRL);
val &= GICC_DIS_BYPASS_MASK;
val |= GICC_ENABLE;
sys_write32(val, GICC_CTRL);
}

static void gic_irq_enable(struct device *dev, unsigned int irq)
{
int int_grp, int_off;

irq += GIC_SPI_INT_BASE;
int_grp = irq / 32;
int_off = irq % 32;

sys_write32((1 << int_off), (GICD_ISENABLERn + int_grp * 4));
}

static void gic_irq_disable(struct device *dev, unsigned int irq)
{
int int_grp, int_off;

irq += GIC_SPI_INT_BASE;
int_grp = irq / 32;
int_off = irq % 32;

sys_write32((1 << int_off), (GICD_ICENABLERn + int_grp * 4));
}

static unsigned int gic_irq_get_state(struct device *dev)
{
return 1;
}

static void gic_irq_set_priority(struct device *dev,
unsigned int irq, unsigned int prio, u32_t flags)
{
int int_grp, int_off;
u8_t val;

irq += GIC_SPI_INT_BASE;

/* Set priority */
sys_write8(prio & 0xff, GICD_IPRIORITYRn + irq);

/* Set interrupt type */
int_grp = irq / 4;
int_off = (irq % 4) * 2;

val = sys_read8(GICD_ICFGRn + int_grp);
val &= ~(GIC_INT_TYPE_MASK << int_off);
if (flags & IRQ_TYPE_EDGE)
val |= (GIC_INT_TYPE_EDGE << int_off);
sys_write8(val, GICD_ICFGRn + int_grp);
}

static void gic_isr(void *arg)
{
struct device *dev = arg;
const struct gic_ictl_config *cfg = dev->config->config_info;
void (*gic_isr_handle)(void *);
int irq, isr_offset;

irq = sys_read32(GICC_IAR);
irq &= 0x3ff;

if (irq == NO_GIC_INT_PENDING) {
printk("gic: Invalid interrupt\n");
return;
}

isr_offset = cfg->isr_table_offset + irq - GIC_SPI_INT_BASE;

gic_isr_handle = _sw_isr_table[isr_offset].isr;
if (gic_isr_handle)
gic_isr_handle(_sw_isr_table[isr_offset].arg);
else
printk("gic: no handler found for int %d\n", irq);

/* set to inactive */
sys_write32(irq, GICC_EOIR);
}

static int gic_init(struct device *unused);
static const struct irq_next_level_api gic_apis = {
.intr_enable = gic_irq_enable,
.intr_disable = gic_irq_disable,
.intr_get_state = gic_irq_get_state,
.intr_set_priority = gic_irq_set_priority,
};

static const struct gic_ictl_config gic_config = {
.isr_table_offset = CONFIG_2ND_LVL_ISR_TBL_OFFSET,
};

DEVICE_AND_API_INIT(arm_gic, DT_INST_0_ARM_GIC_LABEL,
gic_init, NULL, &gic_config,
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &gic_apis);

/**
*
* @brief Initialize the GIC device driver
*
*
* @return N/A
*/
#define GIC_PARENT_IRQ 0
#define GIC_PARENT_IRQ_PRI 0
#define GIC_PARENT_IRQ_FLAGS 0
static int gic_init(struct device *unused)
{
IRQ_CONNECT(GIC_PARENT_IRQ, GIC_PARENT_IRQ_PRI, gic_isr,
DEVICE_GET(arm_gic), GIC_PARENT_IRQ_FLAGS);

/* Init of Distributor interface registers */
gic_dist_init();

/* Init CPU interface registers */
gic_cpu_init();

return 0;
}
@@ -0,0 +1,29 @@
#
# Copyright (c) 2018 Marvell
#
# SPDX-License-Identifier: Apache-2.0
#
---
title: ARMv7-R Generic Interrupt Controller

description: >
This binding describes the ARM Generic Interrupt Controller.
inherits:
!include base.yaml

properties:
compatible:
constraint: "arm,gic"

reg:
category: required

label:
category: required

"#cells":
- irq
- priority
- flags
...
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2018 Lexmark International, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __DT_BINDING_ARM_GIC_H
#define __DT_BINDING_ARM_GIC_H

/* CPU Interrupt numbers */
#define GIC_INT_VIRT_MAINT 25

This comment has been minimized.

Copy link
@galak

galak Nov 15, 2018

Contributor

These values seem like the would be platform/SoC specific?

This comment has been minimized.

Copy link
@bbolen

bbolen Nov 19, 2018

Author

They are called out in the general GIC400 datasheet, http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0471b/index.html section 2.3.2...

#define GIC_INT_HYP_TIMER 26
#define GIC_INT_VIRT_TIMER 27
#define GIC_INT_LEGACY_FIQ 28
#define GIC_INT_PHYS_TIMER 29
#define GIC_INT_NS_PHYS_TIMER 30
#define GIC_INT_LEGACY_IRQ 31

#define IRQ_TYPE_LEVEL 0x0
#define IRQ_TYPE_EDGE 0x1

#define IRQ_DEFAULT_PRIORITY 0xa

#endif
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.