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  */
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(&regs->ctrl[group].int_control_grp, flags);
59 
60 	return 0;
61 }
62 
63 /*
64  * configure the moderation timer resolution for a given group
65  */
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(&regs->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(&regs->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  */
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(&regs->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(&regs->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  */
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(&regs->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(&regs->grp_int_mod[group][vector].grp_int_mod_reg, reg);
127 
128 	return 0;
129 }
130 
131 /*
132  * configure the vmid attributes for a given msix vector.
133  */
134 int al_iofic_msix_vmid_attributes_config(void __iomem *regs_base, int group,
135 				       uint8_t vector, uint32_t vmid, uint8_t vmid_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_VMID_MASK,
145 			 INT_MSIX_VMID_SHIFT,
146 			 vmid);
147 	AL_REG_BIT_VAL_SET(reg,
148 			 INT_MSIX_VMID_EN_SHIFT,
149 			 vmid_en);
150 
151 	al_reg_write32(&regs->grp_int_mod[group][vector].grp_int_vmid_reg, reg);
152 
153 	return 0;
154 }
155 
156 /*
157  * return the offset of the unmask register for a given group
158  */
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 &regs->ctrl[group].int_mask_clear_grp;
167 }
168 
169 
170 /*
171  * unmask specific interrupts for a given group
172  */
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(&regs->ctrl[group].int_mask_clear_grp, ~mask);
185 }
186 
187 /*
188  * mask specific interrupts for a given group
189  */
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(&regs->ctrl[group].int_mask_grp);
199 
200 	al_reg_write32(&regs->ctrl[group].int_mask_grp, reg | mask);
201 }
202 
203 /*
204  * read the mask for a given group
205  */
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(&regs->ctrl[group].int_mask_grp);
214 }
215 
216 /*
217  * read interrupt cause register for a given group
218  */
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(&regs->ctrl[group].int_cause_grp);
227 }
228 
229 /*
230  * clear bits in the interrupt cause register for a given group
231  */
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(&regs->ctrl[group].int_cause_grp, ~mask);
241 }
242 
243 /*
244  * Set the cause register for a given group
245  */
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(&regs->ctrl[group].int_cause_set_grp, mask);
254 }
255 
256 
257 /*
258  * unmask specific interrupts from aborting the udma a given group
259  */
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(&regs->ctrl[group].int_abort_msk_grp, mask);
268 
269 }
270 
271 /*
272  * trigger all interrupts that are waiting for moderation timers to expire
273  */
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(&regs->ctrl[group].int_control_grp);
286 	reg |= INT_CONTROL_GRP_MOD_RST;
287 
288 	al_reg_write32(&regs->ctrl[group].int_control_grp, reg);
289 }
290 
291 /** @} end of interrupt controller group */
292