During driver rewrite, the field to specify the base address of the interrupt controller was dropped, which results in error in device initialization due to accessing random address (or null). Fix it by specifying the base address. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
151 lines
3.9 KiB
C
151 lines
3.9 KiB
C
/*
|
|
* Copyright (c) 2017 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/* This implementation supports only the regular irqs
|
|
* No support for priority filtering
|
|
* No support for vectored interrupts
|
|
* Firqs are also not supported
|
|
* This implementation works only when sw_isr_table is enabled in zephyr
|
|
*/
|
|
|
|
#include <device.h>
|
|
#include <irq_nextlevel.h>
|
|
#include "intc_dw.h"
|
|
#include <soc.h>
|
|
|
|
static ALWAYS_INLINE void dw_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 int dw_ictl_initialize(struct device *dev)
|
|
{
|
|
const struct dw_ictl_config *config = dev->config->config_info;
|
|
volatile struct dw_ictl_registers * const regs =
|
|
(struct dw_ictl_registers *)config->base_addr;
|
|
|
|
/* disable all interrupts */
|
|
regs->irq_inten_l = 0U;
|
|
regs->irq_inten_h = 0U;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void dw_ictl_isr(void *arg)
|
|
{
|
|
struct device *dev = (struct device *)arg;
|
|
const struct dw_ictl_config *config = dev->config->config_info;
|
|
volatile struct dw_ictl_registers * const regs =
|
|
(struct dw_ictl_registers *)config->base_addr;
|
|
|
|
dw_ictl_dispatch_child_isrs(regs->irq_maskstatus_l,
|
|
config->isr_table_offset);
|
|
|
|
if (config->numirqs > 32) {
|
|
dw_ictl_dispatch_child_isrs(regs->irq_maskstatus_h,
|
|
config->isr_table_offset + 32);
|
|
}
|
|
}
|
|
|
|
static inline void dw_ictl_intr_enable(struct device *dev, unsigned int irq)
|
|
{
|
|
const struct dw_ictl_config *config = dev->config->config_info;
|
|
volatile struct dw_ictl_registers * const regs =
|
|
(struct dw_ictl_registers *)config->base_addr;
|
|
|
|
if (irq < 32) {
|
|
regs->irq_inten_l |= (1 << irq);
|
|
} else {
|
|
regs->irq_inten_h |= (1 << (irq - 32));
|
|
}
|
|
}
|
|
|
|
static inline void dw_ictl_intr_disable(struct device *dev, unsigned int irq)
|
|
{
|
|
const struct dw_ictl_config *config = dev->config->config_info;
|
|
volatile struct dw_ictl_registers * const regs =
|
|
(struct dw_ictl_registers *)config->base_addr;
|
|
|
|
if (irq < 32) {
|
|
regs->irq_inten_l &= ~(1 << irq);
|
|
} else {
|
|
regs->irq_inten_h &= ~(1 << (irq - 32));
|
|
}
|
|
}
|
|
|
|
static inline unsigned int dw_ictl_intr_get_state(struct device *dev)
|
|
{
|
|
const struct dw_ictl_config *config = dev->config->config_info;
|
|
volatile struct dw_ictl_registers * const regs =
|
|
(struct dw_ictl_registers *)config->base_addr;
|
|
|
|
if (regs->irq_inten_l) {
|
|
return 1;
|
|
}
|
|
|
|
if (config->numirqs > 32) {
|
|
if (regs->irq_inten_h) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int dw_ictl_intr_get_line_state(struct device *dev, unsigned int irq)
|
|
{
|
|
const struct dw_ictl_config *config = dev->config->config_info;
|
|
volatile struct dw_ictl_registers * const regs =
|
|
(struct dw_ictl_registers *)config->base_addr;
|
|
|
|
if (config->numirqs > 32) {
|
|
if ((regs->irq_inten_h & BIT(irq - 32)) != 0) {
|
|
return 1;
|
|
}
|
|
} else {
|
|
if ((regs->irq_inten_l & BIT(irq)) != 0) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void dw_ictl_config_irq(struct device *dev);
|
|
|
|
static const struct dw_ictl_config dw_config = {
|
|
.base_addr = DT_INTC_DW_0_BASE_ADDR,
|
|
.numirqs = DT_INTC_DW_0_NUM_IRQS,
|
|
.isr_table_offset = CONFIG_DW_ISR_TBL_OFFSET,
|
|
.config_func = dw_ictl_config_irq,
|
|
};
|
|
|
|
static const struct irq_next_level_api dw_ictl_apis = {
|
|
.intr_enable = dw_ictl_intr_enable,
|
|
.intr_disable = dw_ictl_intr_disable,
|
|
.intr_get_state = dw_ictl_intr_get_state,
|
|
.intr_get_line_state = dw_ictl_intr_get_line_state,
|
|
};
|
|
|
|
DEVICE_AND_API_INIT(dw_ictl, DT_INTC_DW_0_NAME, dw_ictl_initialize,
|
|
NULL, &dw_config,
|
|
POST_KERNEL, CONFIG_DW_ICTL_INIT_PRIORITY, &dw_ictl_apis);
|
|
|
|
static void dw_ictl_config_irq(struct device *port)
|
|
{
|
|
IRQ_CONNECT(DT_INTC_DW_0_IRQ, DT_INTC_DW_0_IRQ_PRI, dw_ictl_isr,
|
|
DEVICE_GET(dw_ictl), DT_INTC_DW_0_IRQ_FLAGS);
|
|
}
|