1 /*-
2 *******************************************************************************
3 Copyright (C) 2015 Annapurna Labs Ltd.
4
5 This file may be licensed under the terms of the Annapurna Labs Commercial
6 License Agreement.
7
8 Alternatively, this file can be distributed under the terms of the GNU General
9 Public License V2 as published by the Free Software Foundation and can be
10 found at http://www.gnu.org/licenses/gpl-2.0.html
11
12 Alternatively, redistribution and use in source and binary forms, with or
13 without modification, are permitted provided that the following conditions are
14 met:
15
16 * Redistributions of source code must retain the above copyright notice,
17 this list of conditions and the following disclaimer.
18
19 * Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in
21 the documentation and/or other materials provided with the
22 distribution.
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
28 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35 *******************************************************************************/
36
37 /**
38 * @{
39 * @file al_hal_iofic.c
40 *
41 * @brief interrupt controller hal
42 *
43 */
44
45 #include "al_hal_iofic.h"
46 #include "al_hal_iofic_regs.h"
47
48 /*
49 * configure the interrupt registers, interrupts will are kept masked
50 */
al_iofic_config(void __iomem * regs_base,int group,uint32_t flags)51 int al_iofic_config(void __iomem *regs_base, int group, uint32_t flags)
52 {
53 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
54
55 al_assert(regs_base);
56 al_assert(group < AL_IOFIC_MAX_GROUPS);
57
58 al_reg_write32(®s->ctrl[group].int_control_grp, flags);
59
60 return 0;
61 }
62
63 /*
64 * configure the moderation timer resolution for a given group
65 */
al_iofic_moder_res_config(void __iomem * regs_base,int group,uint8_t resolution)66 int al_iofic_moder_res_config(void __iomem *regs_base, int group,
67 uint8_t resolution)
68
69 {
70 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
71 uint32_t reg;
72
73 al_assert(regs_base);
74 al_assert(group < AL_IOFIC_MAX_GROUPS);
75
76 reg = al_reg_read32(®s->ctrl[group].int_control_grp);
77 AL_REG_FIELD_SET(reg,
78 INT_CONTROL_GRP_MOD_RES_MASK,
79 INT_CONTROL_GRP_MOD_RES_SHIFT,
80 resolution);
81 al_reg_write32(®s->ctrl[group].int_control_grp, reg);
82
83 return 0;
84 }
85
86 /*
87 * configure the moderation timer interval for a given legacy interrupt group
88 */
al_iofic_legacy_moder_interval_config(void __iomem * regs_base,int group,uint8_t interval)89 int al_iofic_legacy_moder_interval_config(void __iomem *regs_base, int group,
90 uint8_t interval)
91 {
92 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
93 uint32_t reg;
94
95 al_assert(regs_base);
96 al_assert(group < AL_IOFIC_MAX_GROUPS);
97
98 reg = al_reg_read32(®s->ctrl[group].int_control_grp);
99 AL_REG_FIELD_SET(reg,
100 INT_CONTROL_GRP_MOD_INTV_MASK,
101 INT_CONTROL_GRP_MOD_INTV_SHIFT,
102 interval);
103 al_reg_write32(®s->ctrl[group].int_control_grp, reg);
104
105 return 0;
106 }
107
108
109 /*
110 * configure the moderation timer interval for a given msix vector.
111 */
al_iofic_msix_moder_interval_config(void __iomem * regs_base,int group,uint8_t vector,uint8_t interval)112 int al_iofic_msix_moder_interval_config(void __iomem *regs_base, int group,
113 uint8_t vector, uint8_t interval)
114 {
115 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
116 uint32_t reg;
117
118 al_assert(regs_base);
119 al_assert(group < AL_IOFIC_MAX_GROUPS);
120
121 reg = al_reg_read32(®s->grp_int_mod[group][vector].grp_int_mod_reg);
122 AL_REG_FIELD_SET(reg,
123 INT_MOD_INTV_MASK,
124 INT_MOD_INTV_SHIFT,
125 interval);
126 al_reg_write32(®s->grp_int_mod[group][vector].grp_int_mod_reg, reg);
127
128 return 0;
129 }
130
131 /*
132 * configure the target-id attributes for a given msix vector.
133 */
al_iofic_msix_tgtid_attributes_config(void __iomem * regs_base,int group,uint8_t vector,uint32_t tgtid,uint8_t tgtid_en)134 int al_iofic_msix_tgtid_attributes_config(void __iomem *regs_base, int group,
135 uint8_t vector, uint32_t tgtid, uint8_t tgtid_en)
136 {
137 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
138 uint32_t reg = 0;
139
140 al_assert(regs_base);
141 al_assert(group < AL_IOFIC_MAX_GROUPS);
142
143 AL_REG_FIELD_SET(reg,
144 INT_MSIX_TGTID_MASK,
145 INT_MSIX_TGTID_SHIFT,
146 tgtid);
147 AL_REG_BIT_VAL_SET(reg,
148 INT_MSIX_TGTID_EN_SHIFT,
149 tgtid_en);
150
151 al_reg_write32(®s->grp_int_mod[group][vector].grp_int_tgtid_reg, reg);
152
153 return 0;
154 }
155
156 /*
157 * return the offset of the unmask register for a given group
158 */
al_iofic_unmask_offset_get(void __iomem * regs_base,int group)159 uint32_t __iomem * al_iofic_unmask_offset_get(void __iomem *regs_base, int group)
160 {
161 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
162
163 al_assert(regs_base);
164 al_assert(group < AL_IOFIC_MAX_GROUPS);
165
166 return ®s->ctrl[group].int_mask_clear_grp;
167 }
168
169
170 /*
171 * unmask specific interrupts for a given group
172 */
al_iofic_unmask(void __iomem * regs_base,int group,uint32_t mask)173 void al_iofic_unmask(void __iomem *regs_base, int group, uint32_t mask)
174 {
175 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
176
177 al_assert(regs_base);
178 al_assert(group < AL_IOFIC_MAX_GROUPS);
179
180 /*
181 * use the mask clear register, no need to read the mask register
182 * itself. write 0 to unmask, 1 has no effect
183 */
184 al_reg_write32_relaxed(®s->ctrl[group].int_mask_clear_grp, ~mask);
185 }
186
187 /*
188 * mask specific interrupts for a given group
189 */
al_iofic_mask(void __iomem * regs_base,int group,uint32_t mask)190 void al_iofic_mask(void __iomem *regs_base, int group, uint32_t mask)
191 {
192 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
193 uint32_t reg;
194
195 al_assert(regs_base);
196 al_assert(group < AL_IOFIC_MAX_GROUPS);
197
198 reg = al_reg_read32(®s->ctrl[group].int_mask_grp);
199
200 al_reg_write32(®s->ctrl[group].int_mask_grp, reg | mask);
201 }
202
203 /*
204 * read the mask for a given group
205 */
al_iofic_read_mask(void __iomem * regs_base,int group)206 uint32_t al_iofic_read_mask(void __iomem *regs_base, int group)
207 {
208 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
209
210 al_assert(regs_base);
211 al_assert(group < AL_IOFIC_MAX_GROUPS);
212
213 return al_reg_read32(®s->ctrl[group].int_mask_grp);
214 }
215
216 /*
217 * read interrupt cause register for a given group
218 */
al_iofic_read_cause(void __iomem * regs_base,int group)219 uint32_t al_iofic_read_cause(void __iomem *regs_base, int group)
220 {
221 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
222
223 al_assert(regs_base);
224 al_assert(group < AL_IOFIC_MAX_GROUPS);
225
226 return al_reg_read32(®s->ctrl[group].int_cause_grp);
227 }
228
229 /*
230 * clear bits in the interrupt cause register for a given group
231 */
al_iofic_clear_cause(void __iomem * regs_base,int group,uint32_t mask)232 void al_iofic_clear_cause(void __iomem *regs_base, int group, uint32_t mask)
233 {
234 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
235
236 al_assert(regs_base);
237 al_assert(group < AL_IOFIC_MAX_GROUPS);
238
239 /* inverse mask, writing 1 has no effect */
240 al_reg_write32(®s->ctrl[group].int_cause_grp, ~mask);
241 }
242
243 /*
244 * Set the cause register for a given group
245 */
al_iofic_set_cause(void __iomem * regs_base,int group,uint32_t mask)246 void al_iofic_set_cause(void __iomem *regs_base, int group, uint32_t mask)
247 {
248 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
249
250 al_assert(regs_base);
251 al_assert(group < AL_IOFIC_MAX_GROUPS);
252
253 al_reg_write32(®s->ctrl[group].int_cause_set_grp, mask);
254 }
255
256
257 /*
258 * unmask specific interrupts from aborting the udma a given group
259 */
al_iofic_abort_mask(void __iomem * regs_base,int group,uint32_t mask)260 void al_iofic_abort_mask(void __iomem *regs_base, int group, uint32_t mask)
261 {
262 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
263
264 al_assert(regs_base);
265 al_assert(group < AL_IOFIC_MAX_GROUPS);
266
267 al_reg_write32(®s->ctrl[group].int_abort_msk_grp, mask);
268
269 }
270
271 /*
272 * trigger all interrupts that are waiting for moderation timers to expire
273 */
al_iofic_interrupt_moderation_reset(void __iomem * regs_base,int group)274 void al_iofic_interrupt_moderation_reset(void __iomem *regs_base, int group)
275 {
276 struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
277 uint32_t reg = 0;
278
279 al_assert(regs_base);
280 al_assert(group < AL_IOFIC_MAX_GROUPS);
281
282 al_assert(regs_base);
283 al_assert(group < AL_IOFIC_MAX_GROUPS);
284
285 reg = al_reg_read32(®s->ctrl[group].int_control_grp);
286 reg |= INT_CONTROL_GRP_MOD_RST;
287
288 al_reg_write32(®s->ctrl[group].int_control_grp, reg);
289 }
290
291 /** @} end of interrupt controller group */
292