diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index fe0b9bed18..cbe566f8b7 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -315,6 +315,17 @@ config ARM64_GIC_EOIMODE Enable GICC_CTLR.EOImode, this will separates the priority drop and interrupt deactivation operations. +config ARM64_GICV2M + bool "gicv2m support message irq" + depends on PCI_MSIX + default n + +config ARM64_GICV2_LEGACY_IRQ0 + int "pci legacy irq0 default val" + default 35 + ---help--- + qemu pci legacy irq0 val, not support if val < 0 + endif config ARM64_SEMIHOSTING_HOSTFS diff --git a/arch/arm64/include/qemu/chip.h b/arch/arm64/include/qemu/chip.h index ceb3290289..0503ee5c81 100644 --- a/arch/arm64/include/qemu/chip.h +++ b/arch/arm64/include/qemu/chip.h @@ -43,6 +43,7 @@ #define CONFIG_GICD_BASE 0x8000000 #define CONFIG_GICR_BASE 0x8010000 +#define CONFIG_GICM_BASE 0x8020000 #elif CONFIG_ARM64_GIC_VERSION == 3 || CONFIG_ARM64_GIC_VERSION == 4 diff --git a/arch/arm64/src/common/CMakeLists.txt b/arch/arm64/src/common/CMakeLists.txt index 7f9e95042a..6f8877a37a 100644 --- a/arch/arm64/src/common/CMakeLists.txt +++ b/arch/arm64/src/common/CMakeLists.txt @@ -52,6 +52,9 @@ endif() if(CONFIG_ARM64_GIC_VERSION EQUAL 2) list(APPEND SRCS arm64_gicv2.c) + if(CONFIG_ARM64_GICV2M) + list(APPEND SRCS arm64_gicv2m.c) + endif() endif() if(CONFIG_ARCH_HAVE_MMU) diff --git a/arch/arm64/src/common/Make.defs b/arch/arm64/src/common/Make.defs index 51540dd31a..0c9bf06db0 100644 --- a/arch/arm64/src/common/Make.defs +++ b/arch/arm64/src/common/Make.defs @@ -65,6 +65,9 @@ endif ifeq ($(CONFIG_ARM64_GIC_VERSION),2) CMN_CSRCS += arm64_gicv2.c +ifeq ($(CONFIG_ARM64_GICV2M),y) +CMN_CSRCS += arm64_gicv2m.c +endif endif ifeq ($(CONFIG_ARCH_HAVE_MMU),y) diff --git a/arch/arm64/src/common/arm64_gic.h b/arch/arm64/src/common/arm64_gic.h index de66d61696..191e40aa7c 100644 --- a/arch/arm64/src/common/arm64_gic.h +++ b/arch/arm64/src/common/arm64_gic.h @@ -321,6 +321,11 @@ uint64_t * arm64_decodeirq(uint64_t *regs); void arm64_gic_raise_sgi(unsigned int sgi_id, uint16_t target_list); +int arm64_gicv_irq_trigger(int irq, bool edge); +#ifdef CONFIG_ARM64_GICV2M +int arm64_gic_v2m_initialize(void); +#endif + #ifdef CONFIG_SMP /**************************************************************************** diff --git a/arch/arm64/src/common/arm64_gicv2.c b/arch/arm64/src/common/arm64_gicv2.c index 525298b185..a69c881305 100644 --- a/arch/arm64/src/common/arm64_gicv2.c +++ b/arch/arm64/src/common/arm64_gicv2.c @@ -40,6 +40,7 @@ #include #include +#include #include "arm64_internal.h" #include "arm64_gic.h" @@ -795,57 +796,6 @@ static int gic_validate_dist_version(void) return 0; } -/**************************************************************************** - * Name: arm_gic_irq_trigger - * - * Description: - * Set the trigger type for the specified IRQ source and the current CPU. - * - * Since this API is not supported on all architectures, it should be - * avoided in common implementations where possible. - * - * Input Parameters: - * irq - The interrupt request to modify. - * edge - False: Active HIGH level sensitive, True: Rising edge sensitive - * - * Returned Value: - * Zero (OK) on success; a negated errno value is returned on any failure. - * - ****************************************************************************/ - -static int arm_gic_irq_trigger(int irq, bool edge) -{ - uintptr_t regaddr; - uint32_t regval; - uint32_t intcfg; - - if (irq > GIC_IRQ_SGI15 && irq < NR_IRQS) - { - /* Get the address of the Interrupt Configuration Register for this - * irq. - */ - - regaddr = GIC_ICDICFR(irq); - - /* Get the new Interrupt configuration bit setting */ - - intcfg = (edge ? (INT_ICDICFR_EDGE | INT_ICDICFR_1N) : INT_ICDICFR_1N); - - /* Write the correct interrupt trigger to the Interrupt Configuration - * Register. - */ - - regval = getreg32(regaddr); - regval &= ~GIC_ICDICFR_ID_MASK(irq); - regval |= GIC_ICDICFR_ID(irq, intcfg); - putreg32(regval, regaddr); - - return OK; - } - - return -EINVAL; -} - /**************************************************************************** * Name: arm_gic0_initialize * @@ -907,6 +857,10 @@ static void arm_gic0_initialize(void) putreg32(0x01010101, GIC_ICDIPTR(irq)); /* SPI on CPU0 */ } +#ifdef CONFIG_ARM64_GICV2M + arm64_gic_v2m_initialize(); +#endif + #ifdef CONFIG_SMP /* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */ @@ -1354,6 +1308,57 @@ void up_trigger_irq(int irq, cpu_set_t cpuset) } } +/**************************************************************************** + * Name: arm64_gicv_irq_trigger + * + * Description: + * Set the trigger type for the specified IRQ source and the current CPU. + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + * Input Parameters: + * irq - The interrupt request to modify. + * edge - False: Active HIGH level sensitive, True: Rising edge sensitive + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ****************************************************************************/ + +int arm64_gicv_irq_trigger(int irq, bool edge) +{ + uintptr_t regaddr; + uint32_t regval; + uint32_t intcfg; + + if (irq > GIC_IRQ_SGI15 && irq < NR_IRQS) + { + /* Get the address of the Interrupt Configuration Register for this + * irq. + */ + + regaddr = GIC_ICDICFR(irq); + + /* Get the new Interrupt configuration bit setting */ + + intcfg = (edge ? (INT_ICDICFR_EDGE | INT_ICDICFR_1N) : INT_ICDICFR_1N); + + /* Write the correct interrupt trigger to the Interrupt Configuration + * Register. + */ + + regval = getreg32(regaddr); + regval &= ~GIC_ICDICFR_ID_MASK(irq); + regval |= GIC_ICDICFR_ID(irq, intcfg); + putreg32(regval, regaddr); + + return OK; + } + + return -EINVAL; +} + /**************************************************************************** * Name: arm64_gic_irq_set_priority * @@ -1393,12 +1398,12 @@ void arm64_gic_irq_set_priority(unsigned int intid, unsigned int prio, { if (flags & IRQ_TYPE_EDGE) { - ret = arm_gic_irq_trigger(intid, true); + ret = arm64_gicv_irq_trigger(intid, true); DEBUGASSERT(ret == OK); } else { - ret = arm_gic_irq_trigger(intid, false); + ret = arm64_gicv_irq_trigger(intid, false); DEBUGASSERT(ret == OK); } } @@ -1507,4 +1512,27 @@ void up_send_smp_call(cpu_set_t cpuset) # endif #endif /* CONFIG_SMP */ +/**************************************************************************** + * Name: up_get_legacy_irq + * + * Description: + * Reserve vector for legacy + * + ****************************************************************************/ + +int up_get_legacy_irq(uint32_t devfn, uint8_t line, uint8_t pin) +{ +#if CONFIG_ARM64_GICV2_LEGACY_IRQ0 >= 0 + uint8_t slot; + uint8_t tmp; + + UNUSED(line); + slot = PCI_SLOT(devfn); + tmp = (pin - 1 + slot) % 4; + return CONFIG_ARM64_GICV2_LEGACY_IRQ0 + tmp; +#else + return -ENOTSUP; +#endif +} + #endif /* CONFIG_ARM64_GIC_VERSION == 2 */ diff --git a/arch/arm64/src/common/arm64_gicv2m.c b/arch/arm64/src/common/arm64_gicv2m.c new file mode 100644 index 0000000000..ec9acc4121 --- /dev/null +++ b/arch/arm64/src/common/arm64_gicv2m.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * arch/arm64/src/common/arm64_gicv2m.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "arm64_internal.h" +#include "arm64_gic.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MPCORE_ICM_VBASE CONFIG_GICM_BASE + +/* V2m Registers */ + +#define GIC_V2MTYPER_OFFSET 0x008 +#define GIC_V2MSETSPI_OFFSET 0x040 +#define GIC_V2MTYPER (MPCORE_ICM_VBASE + GIC_V2MTYPER_OFFSET) +#define GIC_V2MSETSPI (MPCORE_ICM_VBASE + GIC_V2MSETSPI_OFFSET) + +#define GIC_V2MTYPES_BASE_SHIFT 16 +#define GIC_V2MTYPES_BASE_MASK 0x3FF +#define GIC_V2MTYPES_NUM_MASK 0x3FF +#define GIC_V2MTYPES_BASE(x) \ + (((x) >> GIC_V2MTYPES_BASE_SHIFT) & GIC_V2MTYPES_NUM_MASK) +#define GIC_V2MTYPES_NUMBER(x) ((x) & GIC_V2MTYPES_NUM_MASK) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct gic_v2m_s +{ + spinlock_t lock; + uint32_t spi_start; + uint32_t spi_number; + unsigned long *spi_bitmap; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct gic_v2m_s g_v2m = +{ + SP_LOCKED +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static bool is_valid_spi(uint32_t base, uint32_t num) +{ + if (base < GIC_SPI_INT_BASE) + { + return false; + } + + if ((num == 0) || (base + num > NR_IRQS)) + { + return false; + } + + return true; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int arm64_gic_v2m_initialize(void) +{ + uint32_t typer; + + typer = getreg32(GIC_V2MTYPER); + g_v2m.spi_start = GIC_V2MTYPES_BASE(typer); + g_v2m.spi_number = GIC_V2MTYPES_NUMBER(typer); + + if (!is_valid_spi(g_v2m.spi_start, g_v2m.spi_number)) + { + return -EINVAL; + } + + g_v2m.spi_bitmap = kmm_zalloc(BITS_TO_LONGS(g_v2m.spi_number)); + if (g_v2m.spi_bitmap == NULL) + { + return -ENOMEM; + } + + return 0; +} + +int up_alloc_irq_msi(FAR int *num) +{ + irqstate_t flags; + int offset; + int irq; + int i; + + flags = spin_lock_irqsave(&g_v2m.lock); + offset = bitmap_find_free_region(g_v2m.spi_bitmap, g_v2m.spi_number, *num); + spin_unlock_irqrestore(&g_v2m.lock, flags); + irq = g_v2m.spi_start + offset; + for (i = 0; i < *num; i++) + { + arm64_gicv_irq_trigger(i + irq, true); + } + + return irq; +} + +void up_release_irq_msi(FAR int *irq, int num) +{ + irqstate_t flags; + + flags = spin_lock_irqsave(&g_v2m.lock); + bitmap_release_region(g_v2m.spi_bitmap, *irq - g_v2m.spi_start, num); + spin_unlock_irqrestore(&g_v2m.lock, flags); +} + +int up_connect_irq(FAR int *irq, int num, + FAR uintptr_t *mar, FAR uint32_t *mdr) +{ + *mar = GIC_V2MSETSPI; + *mdr = *irq; + return 0; +}