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:
Rajavardhan Gundi 2017-10-12 18:32:23 +05:30 committed by Anas Nashif
parent e3f2fa4f89
commit dadf9e7a81
7 changed files with 266 additions and 6 deletions

View file

@ -0,0 +1,3 @@
zephyr_library()
zephyr_library_include_directories(${PROJECT_SOURCE_DIR}/drivers)
zephyr_library_sources(soc.c)

View 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));
}
}
}

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -6,7 +6,6 @@
# SPDX-License-Identifier: Apache-2.0
#
menu "Interrupt Controllers"
config LOAPIC

View file

@ -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);
}