1/*-
2*******************************************************************************
3Copyright (C) 2015 Annapurna Labs Ltd.
4
5This file may be licensed under the terms of the Annapurna Labs Commercial
6License Agreement.
7
8Alternatively, this file can be distributed under the terms of the GNU General
9Public License V2 as published by the Free Software Foundation and can be
10found at http://www.gnu.org/licenses/gpl-2.0.html
11
12Alternatively, redistribution and use in source and binary forms, with or
13without modification, are permitted provided that the following conditions are
14met:
15
16    *     Redistributions of source code must retain the above copyright notice,
17this list of conditions and the following disclaimer.
18
19    *     Redistributions in binary form must reproduce the above copyright
20notice, this list of conditions and the following disclaimer in
21the documentation and/or other materials provided with the
22distribution.
23
24THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
28ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31ANY 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
33SOFTWARE, 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 */
51int 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 */
66int 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 */
89int 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 */
112int 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 */
134int 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 */
159uint32_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 */
173void 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 */
190void 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 */
206uint32_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 */
219uint32_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 */
232void 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 */
246void 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 */
260void 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 */
274void 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