drivers: interrupts: introduce CAVS interrupt logic
CAVS interrupt logic is an intel IP that combines several sources of interrupt into one line that is then routed to the parent controller. CAVS stands for "connected Audio, Voice and Speech". This IP supports 4 lines which can have a max of 32 interrupts each. Change-Id: Ia6be51428bedf1011d148ae1fc5d4c34252c05da Signed-off-by: Rajavardhan Gundi <rajavardhan.gundi@intel.com> Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
9cc381c07a
commit
74016bb64c
6 changed files with 399 additions and 0 deletions
|
@ -7,3 +7,4 @@ zephyr_sources_ifdef(CONFIG_PIC_DISABLE i8259.c)
|
|||
zephyr_sources_ifdef(CONFIG_PLIC_FE310 plic_fe310.c)
|
||||
zephyr_sources_ifdef(CONFIG_SHARED_IRQ shared_irq.c)
|
||||
zephyr_sources_ifdef(CONFIG_SOC_FAMILY_STM32 exti_stm32.c)
|
||||
zephyr_sources_ifdef(CONFIG_CAVS_ICTL cavs_ictl.c)
|
||||
|
|
|
@ -130,4 +130,6 @@ source "drivers/interrupt_controller/Kconfig.stm32"
|
|||
|
||||
source "drivers/interrupt_controller/Kconfig.multilevel"
|
||||
|
||||
source "drivers/interrupt_controller/Kconfig.s1000"
|
||||
|
||||
endmenu
|
||||
|
|
68
drivers/interrupt_controller/Kconfig.s1000
Normal file
68
drivers/interrupt_controller/Kconfig.s1000
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Kconfig - Intel_S1000 configuration
|
||||
#
|
||||
# Copyright (c) 2017 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
config CAVS_ICTL
|
||||
bool "CAVS Interrupt Logic"
|
||||
default n
|
||||
depends on MULTI_LEVEL_INTERRUPTS
|
||||
help
|
||||
These are 4 in number supporting a max of 32 interrupts each.
|
||||
|
||||
config CAVS_ISR_TBL_OFFSET
|
||||
int "Offset in the SW ISR Table"
|
||||
default 0
|
||||
depends on CAVS_ICTL
|
||||
help
|
||||
This indicates the offset in the SW_ISR_TABLE beginning from where
|
||||
the ISRs for CAVS Interrupt Controller are assigned.
|
||||
|
||||
config CAVS_ICTL_0_NAME
|
||||
string "CAVS 0 Driver name"
|
||||
depends on CAVS_ICTL
|
||||
default "CAVS_0"
|
||||
|
||||
config CAVS_ICTL_0_OFFSET
|
||||
hex "Parent interrupt number to which CAVS_0 maps"
|
||||
default 0x00
|
||||
depends on CAVS_ICTL
|
||||
|
||||
config CAVS_ICTL_1_NAME
|
||||
string "CAVS 1 Driver name"
|
||||
depends on CAVS_ICTL
|
||||
default "CAVS_1"
|
||||
|
||||
config CAVS_ICTL_1_OFFSET
|
||||
hex "Parent interrupt number to which CAVS_1 maps"
|
||||
default 0x00
|
||||
depends on CAVS_ICTL
|
||||
|
||||
config CAVS_ICTL_2_NAME
|
||||
string "CAVS 2 Driver name"
|
||||
depends on CAVS_ICTL
|
||||
default "CAVS_2"
|
||||
|
||||
config CAVS_ICTL_2_OFFSET
|
||||
hex "Parent interrupt number to which CAVS_2 maps"
|
||||
default 0x00
|
||||
depends on CAVS_ICTL
|
||||
|
||||
config CAVS_ICTL_3_NAME
|
||||
string "CAVS 3 Driver name"
|
||||
depends on CAVS_ICTL
|
||||
default "CAVS_3"
|
||||
|
||||
config CAVS_ICTL_3_OFFSET
|
||||
hex "Parent interrupt number to which CAVS_3 maps"
|
||||
default 0x00
|
||||
depends on CAVS_ICTL
|
||||
|
||||
config CAVS_ICTL_INIT_PRIORITY
|
||||
int "CAVS ICTL Init priority"
|
||||
default 60
|
||||
depends on CAVS_ICTL
|
||||
help
|
||||
Cavs Interrupt Logic initialization priority.
|
194
drivers/interrupt_controller/cavs_ictl.c
Normal file
194
drivers/interrupt_controller/cavs_ictl.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <board.h>
|
||||
#include <irq_nextlevel.h>
|
||||
#include "cavs_ictl.h"
|
||||
|
||||
static ALWAYS_INLINE void cavs_ictl_dispatch_child_isrs(u32_t intr_status,
|
||||
u32_t isr_base_offset)
|
||||
{
|
||||
u32_t intr_bitpos, intr_offset;
|
||||
|
||||
/* Dispatch lower level ISRs depending upon the bit set */
|
||||
while (intr_status) {
|
||||
intr_bitpos = find_lsb_set(intr_status) - 1;
|
||||
intr_status &= ~(1 << intr_bitpos);
|
||||
intr_offset = isr_base_offset + intr_bitpos;
|
||||
_sw_isr_table[intr_offset].isr(
|
||||
_sw_isr_table[intr_offset].arg);
|
||||
}
|
||||
}
|
||||
|
||||
static void cavs_ictl_isr(void *arg)
|
||||
{
|
||||
struct device *port = (struct device *)arg;
|
||||
struct cavs_ictl_runtime *context = port->driver_data;
|
||||
|
||||
const struct cavs_ictl_config *config = port->config->config_info;
|
||||
|
||||
volatile struct cavs_registers * const regs =
|
||||
(struct cavs_registers *)context->base_addr;
|
||||
|
||||
cavs_ictl_dispatch_child_isrs(regs->status_il,
|
||||
config->isr_table_offset);
|
||||
}
|
||||
|
||||
static inline void cavs_ictl_irq_enable(struct device *dev, unsigned int irq)
|
||||
{
|
||||
struct cavs_ictl_runtime *context = dev->driver_data;
|
||||
|
||||
volatile struct cavs_registers * const regs =
|
||||
(struct cavs_registers *)context->base_addr;
|
||||
|
||||
regs->enable_il = (1 << irq);
|
||||
}
|
||||
|
||||
static inline void cavs_ictl_irq_disable(struct device *dev, unsigned int irq)
|
||||
{
|
||||
struct cavs_ictl_runtime *context = dev->driver_data;
|
||||
|
||||
volatile struct cavs_registers * const regs =
|
||||
(struct cavs_registers *)context->base_addr;
|
||||
|
||||
regs->disable_il = (1 << irq);
|
||||
}
|
||||
|
||||
static inline unsigned int cavs_ictl_irq_get_state(struct device *dev)
|
||||
{
|
||||
struct cavs_ictl_runtime *context = dev->driver_data;
|
||||
|
||||
volatile struct cavs_registers * const regs =
|
||||
(struct cavs_registers *)context->base_addr;
|
||||
|
||||
/* When the bits of this register are set, it means the
|
||||
* corresponding interrupts are disabled. This function
|
||||
* returns 0 only if ALL the interrupts are disabled.
|
||||
*/
|
||||
if (regs->disable_state_il == 0xFFFFFFFF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct irq_next_level_api cavs_apis = {
|
||||
.intr_enable = cavs_ictl_irq_enable,
|
||||
.intr_disable = cavs_ictl_irq_disable,
|
||||
.intr_get_state = cavs_ictl_irq_get_state,
|
||||
};
|
||||
|
||||
static int cavs_ictl_0_initialize(struct device *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cavs_config_0_irq(struct device *port);
|
||||
|
||||
static const struct cavs_ictl_config cavs_config_0 = {
|
||||
.irq_num = CAVS_ICTL_0_IRQ,
|
||||
.isr_table_offset = CONFIG_CAVS_ISR_TBL_OFFSET,
|
||||
.config_func = cavs_config_0_irq,
|
||||
};
|
||||
|
||||
static struct cavs_ictl_runtime cavs_0_runtime = {
|
||||
.base_addr = CAVS_ICTL_BASE_ADDR,
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(cavs_ictl_0, CONFIG_CAVS_ICTL_0_NAME,
|
||||
cavs_ictl_0_initialize, &cavs_0_runtime, &cavs_config_0,
|
||||
POST_KERNEL, CONFIG_CAVS_ICTL_INIT_PRIORITY, &cavs_apis);
|
||||
|
||||
static void cavs_config_0_irq(struct device *port)
|
||||
{
|
||||
IRQ_CONNECT(CAVS_ICTL_0_IRQ, CONFIG_CAVS_ICTL_0_IRQ_PRI, cavs_ictl_isr,
|
||||
DEVICE_GET(cavs_ictl_0), CAVS_ICTL_0_IRQ_FLAGS);
|
||||
}
|
||||
|
||||
static int cavs_ictl_1_initialize(struct device *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cavs_config_1_irq(struct device *port);
|
||||
|
||||
static const struct cavs_ictl_config cavs_config_1 = {
|
||||
.irq_num = CAVS_ICTL_1_IRQ,
|
||||
.isr_table_offset = CONFIG_CAVS_ISR_TBL_OFFSET +
|
||||
CONFIG_MAX_IRQ_PER_AGGREGATOR,
|
||||
.config_func = cavs_config_1_irq,
|
||||
};
|
||||
|
||||
static struct cavs_ictl_runtime cavs_1_runtime = {
|
||||
.base_addr = CAVS_ICTL_BASE_ADDR + sizeof(struct cavs_registers),
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(cavs_ictl_1, CONFIG_CAVS_ICTL_1_NAME,
|
||||
cavs_ictl_1_initialize, &cavs_1_runtime, &cavs_config_1,
|
||||
POST_KERNEL, CONFIG_CAVS_ICTL_INIT_PRIORITY, &cavs_apis);
|
||||
|
||||
static void cavs_config_1_irq(struct device *port)
|
||||
{
|
||||
IRQ_CONNECT(CAVS_ICTL_1_IRQ, CONFIG_CAVS_ICTL_1_IRQ_PRI, cavs_ictl_isr,
|
||||
DEVICE_GET(cavs_ictl_1), CAVS_ICTL_1_IRQ_FLAGS);
|
||||
}
|
||||
|
||||
static int cavs_ictl_2_initialize(struct device *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cavs_config_2_irq(struct device *port);
|
||||
|
||||
static const struct cavs_ictl_config cavs_config_2 = {
|
||||
.irq_num = CAVS_ICTL_2_IRQ,
|
||||
.isr_table_offset = CONFIG_CAVS_ISR_TBL_OFFSET +
|
||||
CONFIG_MAX_IRQ_PER_AGGREGATOR * 2,
|
||||
.config_func = cavs_config_2_irq,
|
||||
};
|
||||
|
||||
static struct cavs_ictl_runtime cavs_2_runtime = {
|
||||
.base_addr = CAVS_ICTL_BASE_ADDR + sizeof(struct cavs_registers) * 2,
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(cavs_ictl_2, CONFIG_CAVS_ICTL_2_NAME,
|
||||
cavs_ictl_2_initialize, &cavs_2_runtime, &cavs_config_2,
|
||||
POST_KERNEL, CONFIG_CAVS_ICTL_INIT_PRIORITY, &cavs_apis);
|
||||
|
||||
static void cavs_config_2_irq(struct device *port)
|
||||
{
|
||||
IRQ_CONNECT(CAVS_ICTL_2_IRQ, CONFIG_CAVS_ICTL_2_IRQ_PRI, cavs_ictl_isr,
|
||||
DEVICE_GET(cavs_ictl_2), CAVS_ICTL_2_IRQ_FLAGS);
|
||||
}
|
||||
|
||||
static int cavs_ictl_3_initialize(struct device *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cavs_config_3_irq(struct device *port);
|
||||
|
||||
static const struct cavs_ictl_config cavs_config_3 = {
|
||||
.irq_num = CAVS_ICTL_3_IRQ,
|
||||
.isr_table_offset = CONFIG_CAVS_ISR_TBL_OFFSET +
|
||||
CONFIG_MAX_IRQ_PER_AGGREGATOR*3,
|
||||
.config_func = cavs_config_3_irq,
|
||||
};
|
||||
|
||||
static struct cavs_ictl_runtime cavs_3_runtime = {
|
||||
.base_addr = CAVS_ICTL_BASE_ADDR + sizeof(struct cavs_registers) * 3,
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(cavs_ictl_3, CONFIG_CAVS_ICTL_3_NAME,
|
||||
cavs_ictl_3_initialize, &cavs_3_runtime, &cavs_config_3,
|
||||
POST_KERNEL, CONFIG_CAVS_ICTL_INIT_PRIORITY, &cavs_apis);
|
||||
|
||||
static void cavs_config_3_irq(struct device *port)
|
||||
{
|
||||
IRQ_CONNECT(CAVS_ICTL_3_IRQ, CONFIG_CAVS_ICTL_3_IRQ_PRI, cavs_ictl_isr,
|
||||
DEVICE_GET(cavs_ictl_3), CAVS_ICTL_3_IRQ_FLAGS);
|
||||
}
|
39
drivers/interrupt_controller/cavs_ictl.h
Normal file
39
drivers/interrupt_controller/cavs_ictl.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _CAVS_ICTL_H_
|
||||
#define _CAVS_ICTL_H_
|
||||
|
||||
#include <zephyr/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*cavs_ictl_config_irq_t)(struct device *port);
|
||||
|
||||
struct cavs_ictl_config {
|
||||
u32_t irq_num;
|
||||
u32_t isr_table_offset;
|
||||
cavs_ictl_config_irq_t config_func;
|
||||
};
|
||||
|
||||
struct cavs_ictl_runtime {
|
||||
u32_t base_addr;
|
||||
};
|
||||
|
||||
struct cavs_registers {
|
||||
u32_t disable_il; /* il_msd - offset 0x00 */
|
||||
u32_t enable_il; /* il_mcd - offset 0x04 */
|
||||
u32_t disable_state_il; /* il_md - offset 0x08 */
|
||||
u32_t status_il; /* il_sd - offset 0x0C */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _CAVS_ICTL_H_ */
|
95
include/irq_nextlevel.h
Normal file
95
include/irq_nextlevel.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Public interface for configuring interrupts
|
||||
*/
|
||||
#ifndef _IRQ_NEXTLEVEL_H_
|
||||
#define _IRQ_NEXTLEVEL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @cond INTERNAL_HIDDEN
|
||||
*
|
||||
* These are for internal use only, so skip these in
|
||||
* public documentation.
|
||||
*/
|
||||
typedef void (*irq_next_level_func_t)(struct device *dev, unsigned int irq);
|
||||
typedef unsigned int (*irq_next_level_get_state_t)(struct device *dev);
|
||||
|
||||
struct irq_next_level_api {
|
||||
irq_next_level_func_t intr_enable;
|
||||
irq_next_level_func_t intr_disable;
|
||||
irq_next_level_get_state_t intr_get_state;
|
||||
};
|
||||
/**
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Enable an IRQ in the next level.
|
||||
*
|
||||
* This routine enables interrupts present in the interrupt controller.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance.
|
||||
* @param irq IRQ to be enabled.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static inline void irq_enable_next_level(struct device *dev, u32_t irq)
|
||||
{
|
||||
const struct irq_next_level_api *api = dev->driver_api;
|
||||
|
||||
api->intr_enable(dev, irq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable an IRQ in the next level.
|
||||
*
|
||||
* This routine disables interrupts present in the interrupt controller.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance.
|
||||
* @param irq IRQ to be disabled.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static inline void irq_disable_next_level(struct device *dev, u32_t irq)
|
||||
{
|
||||
const struct irq_next_level_api *api = dev->driver_api;
|
||||
|
||||
api->intr_disable(dev, irq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get IRQ enable state.
|
||||
*
|
||||
* This routine indicates if any interrupts are enabled in the interrupt
|
||||
* controller.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance.
|
||||
*
|
||||
* @return interrupt enable state, true or false
|
||||
*/
|
||||
static inline unsigned int irq_is_enabled_next_level(struct device *dev)
|
||||
{
|
||||
const struct irq_next_level_api *api = dev->driver_api;
|
||||
|
||||
return api->intr_get_state(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _IRQ_NEXTLEVEL_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue