58d8afb476
Add a level 2 interrupt controller for the RV32M1 SoC. This uses the INTMUX peripheral. As a first customer, convert the timer driver over to using this, adding nodes for the LPTMR peripherals. This lets users select the timer instance they want to use, and what intmux channel they want to route its interrupt to, using DT overlays. Signed-off-by: Marti Bolivar <marti@foundries.io> Signed-off-by: Mike Scott <mike@foundries.io>
112 lines
3.1 KiB
C
112 lines
3.1 KiB
C
/*
|
|
* Copyright (c) 2018 Foundries.io Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifndef SOC_RISCV32_OPENISA_RV32M1_SOC_H_
|
|
#define SOC_RISCV32_OPENISA_RV32M1_SOC_H_
|
|
|
|
#ifndef _ASMLANGUAGE
|
|
|
|
#include "fsl_device_registers.h"
|
|
#include <zephyr/types.h>
|
|
|
|
/*
|
|
* Helpers related to interrupt handling. This SoC has two levels of
|
|
* interrupts.
|
|
*
|
|
* Level 1 interrupts go straight to the SoC. Level 2 interrupts must
|
|
* go through one of the 8 channels in the the INTMUX
|
|
* peripheral. There are 32 level 1 interrupts, including 8 INTMUX
|
|
* interrupts. Each INTMUX interrupt can mux at most
|
|
* CONFIG_MAX_IRQ_PER_AGGREGATOR (which happens to be 32) interrupts
|
|
* to its level 1 interrupt.
|
|
*
|
|
* See gen_isr_tables.py for details on the Zephyr multi-level IRQ
|
|
* number encoding, which determines how these helpers work.
|
|
*/
|
|
|
|
/**
|
|
* @brief Get an IRQ's level
|
|
* @param irq The IRQ number in the Zephyr irq.h numbering system
|
|
* @return IRQ level, either 1 or 2
|
|
*/
|
|
static inline unsigned int rv32m1_irq_level(unsigned int irq)
|
|
{
|
|
return ((irq >> 8) & 0xff) == 0 ? 1 : 2;
|
|
}
|
|
|
|
/**
|
|
* @brief Level 1 interrupt line associated with an IRQ
|
|
*
|
|
* Results are undefined if rv32m1_irq_level(irq) is not 1.
|
|
*
|
|
* @param The IRQ number in the Zephyr <irq.h> numbering system
|
|
* @return Level 1 (i.e. event unit) IRQ number associated with irq
|
|
*/
|
|
static inline u32_t rv32m1_level1_irq(unsigned int irq)
|
|
{
|
|
/*
|
|
* There's no need to do any math; the precondition is that
|
|
* it's a level 1 IRQ.
|
|
*/
|
|
return irq;
|
|
}
|
|
|
|
/**
|
|
* @brief INTMUX channel (i.e. level 2 aggregator number) for an IRQ
|
|
*
|
|
* Results are undefined if rv32m1_irq_level(irq) is not 2.
|
|
*
|
|
* @param irq The IRQ number whose INTMUX channel / level 2 aggregator
|
|
* to get, in the Zephyr <irq.h> numbering system
|
|
* @return INTMUX channel number associated with the IRQ
|
|
*/
|
|
static inline u32_t rv32m1_intmux_channel(unsigned int irq)
|
|
{
|
|
/*
|
|
* Here we make use of these facts:
|
|
*
|
|
* - the INTMUX output IRQ numbers are arranged consecutively
|
|
* by channel in the event unit IRQ numbering assignment,
|
|
* starting from channel 0.
|
|
*
|
|
* - CONFIG_2ND_LVL_INTR_00_OFFSET is defined to
|
|
* be the offset of the first level 2 aggregator in the parent
|
|
* interrupt controller's IRQ numbers, i.e. channel 0's
|
|
* IRQ number in the event unit.
|
|
*/
|
|
return (irq & 0xff) - CONFIG_2ND_LVL_INTR_00_OFFSET;
|
|
}
|
|
|
|
/**
|
|
* @brief INTMUX interrupt ID number for an IRQ
|
|
*
|
|
* Results are undefined if rv32m1_irq_level(irq) is not 2.
|
|
*
|
|
* @param The IRQ number whose INTMUX interrupt ID to get, in the Zephyr
|
|
* <irq.h> numbering system
|
|
* @return The INTMUX interrupt ID, in the inclusive range 0 to 31
|
|
*/
|
|
static inline u32_t rv32m1_intmux_line(unsigned int irq)
|
|
{
|
|
return ((irq >> 8) & 0xff) - 1;
|
|
}
|
|
|
|
void soc_interrupt_init(void);
|
|
|
|
#endif /* !_ASMLANGUAGE */
|
|
|
|
#if defined(CONFIG_SOC_OPENISA_RV32M1_RI5CY)
|
|
#include "soc_ri5cy.h"
|
|
#elif defined(CONFIG_SOC_OPENISA_RV32M1_ZERO_RISCY)
|
|
#include "soc_zero_riscy.h"
|
|
#endif
|
|
|
|
/* Newlib hooks (and potentially other things) use these defines. */
|
|
#define RISCV_RAM_SIZE CONFIG_RISCV32_RV32M1_RAM_SIZE
|
|
#define RISCV_RAM_BASE CONFIG_RISCV32_RV32M1_RAM_BASE_ADDR
|
|
|
|
#endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_H_ */
|