xtensa: intel_s1000: implement interrupt mechanism
intel_s1000 has multiple levels of interrupts consisting of core, CAVS Logic and designware interrupt controller. This patchset modifies the regular gen_isr mechanism to support these multiple levels. Change-Id: I0450666d4e601dfbc8cadc9c9d8100afb61a214c Signed-off-by: Rajavardhan Gundi <rajavardhan.gundi@intel.com> Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
e3f2fa4f89
commit
dadf9e7a81
|
@ -0,0 +1,3 @@
|
|||
zephyr_library()
|
||||
zephyr_library_include_directories(${PROJECT_SOURCE_DIR}/drivers)
|
||||
zephyr_library_sources(soc.c)
|
140
arch/xtensa/soc/intel_s1000/soc.c
Normal file
140
arch/xtensa/soc/intel_s1000/soc.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <xtensa_api.h>
|
||||
#include <xtensa/xtruntime.h>
|
||||
#include <logging/sys_log.h>
|
||||
#include <board.h>
|
||||
#include <irq_nextlevel.h>
|
||||
|
||||
void _soc_irq_enable(u32_t irq)
|
||||
{
|
||||
struct device *dev_cavs, *dev_ictl;
|
||||
|
||||
switch (XTENSA_IRQ_NUMBER(irq)) {
|
||||
case CAVS_ICTL_0_IRQ:
|
||||
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_0_NAME);
|
||||
break;
|
||||
case CAVS_ICTL_1_IRQ:
|
||||
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_1_NAME);
|
||||
break;
|
||||
case CAVS_ICTL_2_IRQ:
|
||||
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_2_NAME);
|
||||
break;
|
||||
case CAVS_ICTL_3_IRQ:
|
||||
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_3_NAME);
|
||||
break;
|
||||
default:
|
||||
/* regular interrupt */
|
||||
_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev_cavs) {
|
||||
SYS_LOG_DBG("board: CAVS device binding failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the control comes here it means the specified interrupt
|
||||
* is in either CAVS interrupt logic or DW interrupt controller
|
||||
*/
|
||||
_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq));
|
||||
|
||||
switch (CAVS_IRQ_NUMBER(irq)) {
|
||||
case DW_ICTL_IRQ_CAVS_OFFSET:
|
||||
dev_ictl = device_get_binding(CONFIG_DW_ICTL_NAME);
|
||||
break;
|
||||
default:
|
||||
/* The source of the interrupt is in CAVS interrupt logic */
|
||||
irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev_ictl) {
|
||||
SYS_LOG_DBG("board: DW intr_control device binding failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the control comes here it means the specified interrupt
|
||||
* is in DW interrupt controller
|
||||
*/
|
||||
irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
|
||||
|
||||
/* Manipulate the relevant bit in the interrupt controller
|
||||
* register as needed
|
||||
*/
|
||||
irq_enable_next_level(dev_ictl, INTR_CNTL_IRQ_NUM(irq));
|
||||
}
|
||||
|
||||
void _soc_irq_disable(u32_t irq)
|
||||
{
|
||||
struct device *dev_cavs, *dev_ictl;
|
||||
|
||||
switch (XTENSA_IRQ_NUMBER(irq)) {
|
||||
case CAVS_ICTL_0_IRQ:
|
||||
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_0_NAME);
|
||||
break;
|
||||
case CAVS_ICTL_1_IRQ:
|
||||
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_1_NAME);
|
||||
break;
|
||||
case CAVS_ICTL_2_IRQ:
|
||||
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_2_NAME);
|
||||
break;
|
||||
case CAVS_ICTL_3_IRQ:
|
||||
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_3_NAME);
|
||||
break;
|
||||
default:
|
||||
/* regular interrupt */
|
||||
_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev_cavs) {
|
||||
SYS_LOG_DBG("board: CAVS device binding failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the control comes here it means the specified interrupt
|
||||
* is in either CAVS interrupt logic or DW interrupt controller
|
||||
*/
|
||||
|
||||
switch (CAVS_IRQ_NUMBER(irq)) {
|
||||
case DW_ICTL_IRQ_CAVS_OFFSET:
|
||||
dev_ictl = device_get_binding(CONFIG_DW_ICTL_NAME);
|
||||
break;
|
||||
default:
|
||||
/* The source of the interrupt is in CAVS interrupt logic */
|
||||
irq_disable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
|
||||
|
||||
/* Disable the parent IRQ if all children are disabled */
|
||||
if (!irq_is_enabled_next_level(dev_cavs)) {
|
||||
_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev_ictl) {
|
||||
SYS_LOG_DBG("board: DW intr_control device binding failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the control comes here it means the specified interrupt
|
||||
* is in DW interrupt controller.
|
||||
* Manipulate the relevant bit in the interrupt controller
|
||||
* register as needed
|
||||
*/
|
||||
irq_disable_next_level(dev_ictl, INTR_CNTL_IRQ_NUM(irq));
|
||||
|
||||
/* Disable the parent IRQ if all children are disabled */
|
||||
if (!irq_is_enabled_next_level(dev_ictl)) {
|
||||
irq_disable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
|
||||
|
||||
if (!irq_is_enabled_next_level(dev_cavs)) {
|
||||
_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,21 +6,73 @@
|
|||
#ifndef __INC_SOC_H
|
||||
#define __INC_SOC_H
|
||||
|
||||
/* macros related to interrupt handling */
|
||||
#define XTENSA_IRQ_NUM_SHIFT 0
|
||||
#define CAVS_IRQ_NUM_SHIFT 8
|
||||
#define INTR_CNTL_IRQ_NUM_SHIFT 16
|
||||
#define XTENSA_IRQ_NUM_MASK 0xff
|
||||
#define CAVS_IRQ_NUM_MASK 0xff
|
||||
#define INTR_CNTL_IRQ_NUM_MASK 0xff
|
||||
|
||||
/*
|
||||
* IRQs are mapped on 3 levels. 4th level is left 0x00.
|
||||
*
|
||||
* 1. Peripheral Register bit offset.
|
||||
* 2. CAVS logic bit offset.
|
||||
* 3. Core interrupt number.
|
||||
*/
|
||||
#define XTENSA_IRQ_NUMBER(_irq) \
|
||||
((_irq >> XTENSA_IRQ_NUM_SHIFT) & XTENSA_IRQ_NUM_MASK)
|
||||
#define CAVS_IRQ_NUMBER(_irq) \
|
||||
(((_irq >> CAVS_IRQ_NUM_SHIFT) & CAVS_IRQ_NUM_MASK) - 1)
|
||||
#define INTR_CNTL_IRQ_NUM(_irq) \
|
||||
(((_irq >> INTR_CNTL_IRQ_NUM_SHIFT) & INTR_CNTL_IRQ_NUM_MASK) - 1)
|
||||
|
||||
/* CAVS interrupt logic */
|
||||
#define CAVS_ICTL_BASE_ADDR 0x00078800
|
||||
#define CAVS_ICTL_0_IRQ 0x00000006
|
||||
#define CAVS_ICTL_0_IRQ_FLAGS 0
|
||||
|
||||
#define CAVS_ICTL_1_IRQ 0x0000000A
|
||||
#define CAVS_ICTL_1_IRQ_FLAGS 0
|
||||
|
||||
#define CAVS_ICTL_2_IRQ 0x0000000D
|
||||
#define CAVS_ICTL_2_IRQ_FLAGS 0
|
||||
|
||||
#define CAVS_ICTL_3_IRQ 0x00000010
|
||||
#define CAVS_ICTL_3_IRQ_FLAGS 0
|
||||
|
||||
/* DW interrupt controller */
|
||||
#define DW_ICTL_BASE_ADDR 0x00081800
|
||||
#define DW_ICTL_IRQ 0x00000706
|
||||
#define DW_ICTL_IRQ_CAVS_OFFSET CAVS_IRQ_NUMBER(DW_ICTL_IRQ)
|
||||
#define DW_ICTL_NUM_IRQS 9
|
||||
#define DW_ICTL_IRQ_FLAGS 0
|
||||
|
||||
/* GPIO */
|
||||
#define GPIO_DW_0_BASE_ADDR 0x00080C00
|
||||
#define GPIO_DW_0_BITS 32
|
||||
#define GPIO_DW_PORT_0_INT_MASK 0
|
||||
#define GPIO_DW_0_IRQ_FLAGS 0
|
||||
#define GPIO_DW_0_IRQ 20
|
||||
#define GPIO_DW_0_IRQ 0x00040706
|
||||
#define GPIO_DW_0_IRQ_ICTL_OFFSET INTR_CNTL_IRQ_NUM(GPIO_DW_0_IRQ)
|
||||
|
||||
/* UART - UART0 */
|
||||
#define UART_NS16550_PORT_0_BASE_ADDR 0x00080800
|
||||
#define UART_NS16550_PORT_0_CLK_FREQ 38400000
|
||||
#define UART_NS16550_PORT_0_IRQ 0x00030706
|
||||
#define UART_NS16550_P0_IRQ_ICTL_OFFSET INTR_CNTL_IRQ_NUM(\
|
||||
UART_NS16550_PORT_0_IRQ)
|
||||
#define UART_IRQ_FLAGS 0
|
||||
|
||||
/* I2C - I2C0 */
|
||||
#define I2C_DW_0_BASE_ADDR 0x00080400
|
||||
#define I2C_DW_0_IRQ 20
|
||||
#define I2C_DW_0_IRQ 0x00020706
|
||||
#define I2C_DW_0_IRQ_ICTL_OFFSET INTR_CNTL_IRQ_NUM(I2C_DW_0_IRQ)
|
||||
#define I2C_DW_IRQ_FLAGS 0
|
||||
#define I2C_DW_CLOCK_SPEED 38
|
||||
|
||||
extern void _soc_irq_enable(u32_t irq);
|
||||
extern void _soc_irq_disable(u32_t irq);
|
||||
|
||||
#endif /* __INC_SOC_H */
|
||||
|
|
|
@ -10,6 +10,45 @@ config BOARD
|
|||
config BOARD_XTENSA
|
||||
def_bool y
|
||||
|
||||
config CAVS_ICTL_0_OFFSET
|
||||
default 0x06
|
||||
config CAVS_ICTL_1_OFFSET
|
||||
default 0x0A
|
||||
config CAVS_ICTL_2_OFFSET
|
||||
default 0x0D
|
||||
config CAVS_ICTL_3_OFFSET
|
||||
default 0x10
|
||||
|
||||
config DW_ICTL_OFFSET
|
||||
default 0x07
|
||||
|
||||
config 2ND_LVL_INTR_00_OFFSET
|
||||
default CAVS_ICTL_0_OFFSET
|
||||
config 2ND_LVL_INTR_01_OFFSET
|
||||
default CAVS_ICTL_1_OFFSET
|
||||
config 2ND_LVL_INTR_02_OFFSET
|
||||
default CAVS_ICTL_2_OFFSET
|
||||
config 2ND_LVL_INTR_03_OFFSET
|
||||
default CAVS_ICTL_3_OFFSET
|
||||
config 3RD_LVL_INTR_00_OFFSET
|
||||
default DW_ICTL_OFFSET
|
||||
|
||||
config MAX_IRQ_PER_AGGREGATOR
|
||||
default 32
|
||||
config NUM_2ND_LEVEL_AGGREGATORS
|
||||
default 4
|
||||
config NUM_3RD_LEVEL_AGGREGATORS
|
||||
default 1
|
||||
config 2ND_LVL_ISR_TBL_OFFSET
|
||||
default 21
|
||||
config 3RD_LVL_ISR_TBL_OFFSET
|
||||
default 149
|
||||
|
||||
config CAVS_ISR_TBL_OFFSET
|
||||
default 2ND_LVL_ISR_TBL_OFFSET
|
||||
config DW_ISR_TBL_OFFSET
|
||||
default 3RD_LVL_ISR_TBL_OFFSET
|
||||
|
||||
config GPIO_DW_0_NAME
|
||||
default "GPIO_PORTA"
|
||||
config GPIO_DW_0_IRQ_PRI
|
||||
|
@ -33,6 +72,8 @@ config UART_NS16550_PORT_0_BAUD_RATE
|
|||
default 115200
|
||||
config UART_NS16550_PORT_0_OPTIONS
|
||||
default 0
|
||||
config UART_INTERRUPT_DRIVEN
|
||||
def_bool y
|
||||
|
||||
endif # UART_NS16550_PORT_0
|
||||
|
||||
|
|
|
@ -14,6 +14,12 @@ CONFIG_GEN_IRQ_VECTOR_TABLE=n
|
|||
CONFIG_XTENSA_RESET_VECTOR=y
|
||||
CONFIG_XTENSA_USE_CORE_CRT1=y
|
||||
|
||||
CONFIG_MULTI_LEVEL_INTERRUPTS=y
|
||||
CONFIG_2ND_LEVEL_INTERRUPTS=y
|
||||
CONFIG_3RD_LEVEL_INTERRUPTS=y
|
||||
CONFIG_CAVS_ICTL=y
|
||||
CONFIG_DW_ICTL=y
|
||||
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_GPIO_DW=y
|
||||
CONFIG_GPIO_DW_0=y
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
|
||||
menu "Interrupt Controllers"
|
||||
|
||||
config LOAPIC
|
||||
|
|
|
@ -8,9 +8,28 @@
|
|||
|
||||
#include <xtensa_api.h>
|
||||
#include <xtensa/xtruntime.h>
|
||||
#include <board.h>
|
||||
|
||||
#define CONFIG_GEN_IRQ_START_VECTOR 0
|
||||
|
||||
#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS
|
||||
|
||||
#define CONFIG_NUM_IRQS (XCHAL_NUM_INTERRUPTS +\
|
||||
(CONFIG_NUM_2ND_LEVEL_AGGREGATORS +\
|
||||
CONFIG_NUM_3RD_LEVEL_AGGREGATORS) *\
|
||||
CONFIG_MAX_IRQ_PER_AGGREGATOR)
|
||||
|
||||
#define _arch_irq_enable(irq) _soc_irq_enable(irq)
|
||||
#define _arch_irq_disable(irq) _soc_irq_disable(irq)
|
||||
|
||||
#else
|
||||
|
||||
#define CONFIG_NUM_IRQS XCHAL_NUM_INTERRUPTS
|
||||
#define CONFIG_GEN_IRQ_START_VECTOR 0
|
||||
|
||||
#define _arch_irq_enable(irq) _xtensa_irq_enable(irq)
|
||||
#define _arch_irq_disable(irq) _xtensa_irq_disable(irq)
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -22,7 +41,7 @@
|
|||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static ALWAYS_INLINE void _arch_irq_enable(u32_t irq)
|
||||
static ALWAYS_INLINE void _xtensa_irq_enable(u32_t irq)
|
||||
{
|
||||
_xt_ints_on(1 << irq);
|
||||
}
|
||||
|
@ -36,7 +55,7 @@ static ALWAYS_INLINE void _arch_irq_enable(u32_t irq)
|
|||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static ALWAYS_INLINE void _arch_irq_disable(u32_t irq)
|
||||
static ALWAYS_INLINE void _xtensa_irq_disable(u32_t irq)
|
||||
{
|
||||
_xt_ints_off(1 << irq);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue