blob: f80fe058f19b22c3d5606d7aa546e221d191587c [file] [log] [blame]
Rajavardhan Gundie3f2fa42017-10-12 15:44:48 +05301/*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7/* This implementation supports only the regular irqs
8 * No support for priority filtering
9 * No support for vectored interrupts
10 * Firqs are also not supported
11 * This implementation works only when sw_isr_table is enabled in zephyr
12 */
13
14#include <device.h>
15#include <board.h>
16#include <irq_nextlevel.h>
17#include "dw_ictl.h"
18
19static ALWAYS_INLINE void dw_ictl_dispatch_child_isrs(u32_t intr_status,
20 u32_t isr_base_offset)
21{
22 u32_t intr_bitpos, intr_offset;
23
24 /* Dispatch lower level ISRs depending upon the bit set */
25 while (intr_status) {
26 intr_bitpos = find_lsb_set(intr_status) - 1;
27 intr_status &= ~(1 << intr_bitpos);
28 intr_offset = isr_base_offset + intr_bitpos;
29 _sw_isr_table[intr_offset].isr(
30 _sw_isr_table[intr_offset].arg);
31 }
32}
33
34static int dw_ictl_initialize(struct device *port)
35{
36 struct dw_ictl_runtime *dw = port->driver_data;
37
38 volatile struct dw_ictl_registers * const regs =
39 (struct dw_ictl_registers *)dw->base_addr;
40
41 /* disable all interrupts */
42 regs->irq_inten_l = 0;
43 regs->irq_inten_h = 0;
44
45 return 0;
46}
47
48static void dw_ictl_isr(void *arg)
49{
50 struct device *port = (struct device *)arg;
51 struct dw_ictl_runtime * const dw = port->driver_data;
52
53 const struct dw_ictl_config *config = port->config->config_info;
54
55 volatile struct dw_ictl_registers * const regs =
56 (struct dw_ictl_registers *)dw->base_addr;
57
58 dw_ictl_dispatch_child_isrs(regs->irq_maskstatus_l,
59 config->isr_table_offset);
60
61 if (config->numirqs > 32) {
62 dw_ictl_dispatch_child_isrs(regs->irq_maskstatus_h,
63 config->isr_table_offset + 32);
64 }
65}
66
67static inline void dw_ictl_intr_enable(struct device *dev, unsigned int irq)
68{
69 struct dw_ictl_runtime *context = dev->driver_data;
70
71 volatile struct dw_ictl_registers * const regs =
72 (struct dw_ictl_registers *)context->base_addr;
73
74 if (irq < 32) {
75 regs->irq_inten_l |= (1 << irq);
76 } else {
77 regs->irq_inten_h |= (1 << (irq - 32));
78 }
79}
80
81static inline void dw_ictl_intr_disable(struct device *dev, unsigned int irq)
82{
83 struct dw_ictl_runtime *context = dev->driver_data;
84
85 volatile struct dw_ictl_registers * const regs =
86 (struct dw_ictl_registers *)context->base_addr;
87
88 if (irq < 32) {
89 regs->irq_inten_l &= ~(1 << irq);
90 } else {
91 regs->irq_inten_h &= ~(1 << (irq - 32));
92 }
93}
94
95static inline unsigned int dw_ictl_intr_get_state(struct device *dev)
96{
97 struct dw_ictl_runtime *context = dev->driver_data;
98
99 const struct dw_ictl_config *config = dev->config->config_info;
100
101 volatile struct dw_ictl_registers * const regs =
102 (struct dw_ictl_registers *)context->base_addr;
103
104 if (regs->irq_inten_l) {
105 return 1;
106 }
107
108 if (config->numirqs > 32) {
109 if (regs->irq_inten_h) {
110 return 1;
111 }
112 }
113 return 0;
114}
115
116static void dw_ictl_config_irq(struct device *port);
117
118static const struct dw_ictl_config dw_config = {
119 .irq_num = DW_ICTL_IRQ,
120 .numirqs = DW_ICTL_NUM_IRQS,
121 .isr_table_offset = CONFIG_DW_ISR_TBL_OFFSET,
122 .config_func = dw_ictl_config_irq,
123};
124
125static struct dw_ictl_runtime dw_runtime = {
126 .base_addr = DW_ICTL_BASE_ADDR,
127};
128
129static const struct irq_next_level_api dw_ictl_apis = {
130 .intr_enable = dw_ictl_intr_enable,
131 .intr_disable = dw_ictl_intr_disable,
132 .intr_get_state = dw_ictl_intr_get_state,
133};
134
135DEVICE_AND_API_INIT(dw_ictl, CONFIG_DW_ICTL_NAME, dw_ictl_initialize,
136 &dw_runtime, &dw_config,
137 POST_KERNEL, CONFIG_DW_ICTL_INIT_PRIORITY, &dw_ictl_apis);
138
139static void dw_ictl_config_irq(struct device *port)
140{
141 IRQ_CONNECT(DW_ICTL_IRQ, CONFIG_DW_ICTL_IRQ_PRI, dw_ictl_isr,
142 DEVICE_GET(dw_ictl), DW_ICTL_IRQ_FLAGS);
143}