1294838Szbb/*-
2294838Szbb*******************************************************************************
3294838SzbbCopyright (C) 2015 Annapurna Labs Ltd.
4294838Szbb
5294838SzbbThis file may be licensed under the terms of the Annapurna Labs Commercial
6294838SzbbLicense Agreement.
7294838Szbb
8294838SzbbAlternatively, this file can be distributed under the terms of the GNU General
9294838SzbbPublic License V2 as published by the Free Software Foundation and can be
10294838Szbbfound at http://www.gnu.org/licenses/gpl-2.0.html
11294838Szbb
12294838SzbbAlternatively, redistribution and use in source and binary forms, with or
13294838Szbbwithout modification, are permitted provided that the following conditions are
14294838Szbbmet:
15294838Szbb
16294838Szbb    *     Redistributions of source code must retain the above copyright notice,
17294838Szbbthis list of conditions and the following disclaimer.
18294838Szbb
19294838Szbb    *     Redistributions in binary form must reproduce the above copyright
20294838Szbbnotice, this list of conditions and the following disclaimer in
21294838Szbbthe documentation and/or other materials provided with the
22294838Szbbdistribution.
23294838Szbb
24294838SzbbTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25294838SzbbANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26294838SzbbWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27294838SzbbDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
28294838SzbbANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29294838Szbb(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30294838SzbbLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31294838SzbbANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32294838Szbb(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33294838SzbbSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34294838Szbb
35294838Szbb*******************************************************************************/
36294838Szbb
37294838Szbb/**
38294838Szbb *  @{
39294838Szbb * @file   al_hal_iofic.c
40294838Szbb *
41294838Szbb * @brief  interrupt controller hal
42294838Szbb *
43294838Szbb */
44294838Szbb
45294838Szbb#include "al_hal_iofic.h"
46294838Szbb#include "al_hal_iofic_regs.h"
47294838Szbb
48294838Szbb/*
49294838Szbb * configure the interrupt registers, interrupts will are kept masked
50294838Szbb */
51294838Szbbint al_iofic_config(void __iomem *regs_base, int group, uint32_t flags)
52294838Szbb{
53294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
54294838Szbb
55294838Szbb	al_assert(regs_base);
56294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
57294838Szbb
58294838Szbb	al_reg_write32(&regs->ctrl[group].int_control_grp, flags);
59294838Szbb
60294838Szbb	return 0;
61294838Szbb}
62294838Szbb
63294838Szbb/*
64294838Szbb * configure the moderation timer resolution for a given group
65294838Szbb */
66294838Szbbint al_iofic_moder_res_config(void __iomem *regs_base, int group,
67294838Szbb			     uint8_t resolution)
68294838Szbb
69294838Szbb{
70294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
71294838Szbb	uint32_t reg;
72294838Szbb
73294838Szbb	al_assert(regs_base);
74294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
75294838Szbb
76294838Szbb	reg = al_reg_read32(&regs->ctrl[group].int_control_grp);
77294838Szbb	AL_REG_FIELD_SET(reg,
78294838Szbb			 INT_CONTROL_GRP_MOD_RES_MASK,
79294838Szbb			 INT_CONTROL_GRP_MOD_RES_SHIFT,
80294838Szbb			 resolution);
81294838Szbb	al_reg_write32(&regs->ctrl[group].int_control_grp, reg);
82294838Szbb
83294838Szbb	return 0;
84294838Szbb}
85294838Szbb
86294838Szbb/*
87294838Szbb * configure the moderation timer interval for a given legacy interrupt group
88294838Szbb */
89294838Szbbint al_iofic_legacy_moder_interval_config(void __iomem *regs_base, int group,
90294838Szbb				     uint8_t interval)
91294838Szbb{
92294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
93294838Szbb	uint32_t reg;
94294838Szbb
95294838Szbb	al_assert(regs_base);
96294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
97294838Szbb
98294838Szbb	reg = al_reg_read32(&regs->ctrl[group].int_control_grp);
99294838Szbb	AL_REG_FIELD_SET(reg,
100294838Szbb			 INT_CONTROL_GRP_MOD_INTV_MASK,
101294838Szbb			 INT_CONTROL_GRP_MOD_INTV_SHIFT,
102294838Szbb			 interval);
103294838Szbb	al_reg_write32(&regs->ctrl[group].int_control_grp, reg);
104294838Szbb
105294838Szbb	return 0;
106294838Szbb}
107294838Szbb
108294838Szbb
109294838Szbb/*
110294838Szbb * configure the moderation timer interval for a given msix vector.
111294838Szbb */
112294838Szbbint al_iofic_msix_moder_interval_config(void __iomem *regs_base, int group,
113294838Szbb				       uint8_t vector, uint8_t interval)
114294838Szbb{
115294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
116294838Szbb	uint32_t reg;
117294838Szbb
118294838Szbb	al_assert(regs_base);
119294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
120294838Szbb
121294838Szbb	reg = al_reg_read32(&regs->grp_int_mod[group][vector].grp_int_mod_reg);
122294838Szbb	AL_REG_FIELD_SET(reg,
123294838Szbb			 INT_MOD_INTV_MASK,
124294838Szbb			 INT_MOD_INTV_SHIFT,
125294838Szbb			 interval);
126294838Szbb	al_reg_write32(&regs->grp_int_mod[group][vector].grp_int_mod_reg, reg);
127294838Szbb
128294838Szbb	return 0;
129294838Szbb}
130294838Szbb
131294838Szbb/*
132294838Szbb * configure the vmid attributes for a given msix vector.
133294838Szbb */
134294838Szbbint al_iofic_msix_vmid_attributes_config(void __iomem *regs_base, int group,
135294838Szbb				       uint8_t vector, uint32_t vmid, uint8_t vmid_en)
136294838Szbb{
137294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
138294838Szbb	uint32_t reg = 0;
139294838Szbb
140294838Szbb	al_assert(regs_base);
141294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
142294838Szbb
143294838Szbb	AL_REG_FIELD_SET(reg,
144294838Szbb			 INT_MSIX_VMID_MASK,
145294838Szbb			 INT_MSIX_VMID_SHIFT,
146294838Szbb			 vmid);
147294838Szbb	AL_REG_BIT_VAL_SET(reg,
148294838Szbb			 INT_MSIX_VMID_EN_SHIFT,
149294838Szbb			 vmid_en);
150294838Szbb
151294838Szbb	al_reg_write32(&regs->grp_int_mod[group][vector].grp_int_vmid_reg, reg);
152294838Szbb
153294838Szbb	return 0;
154294838Szbb}
155294838Szbb
156294838Szbb/*
157294838Szbb * return the offset of the unmask register for a given group
158294838Szbb */
159294838Szbbuint32_t __iomem * al_iofic_unmask_offset_get(void __iomem *regs_base, int group)
160294838Szbb{
161294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
162294838Szbb
163294838Szbb	al_assert(regs_base);
164294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
165294838Szbb
166294838Szbb	return &regs->ctrl[group].int_mask_clear_grp;
167294838Szbb}
168294838Szbb
169294838Szbb
170294838Szbb/*
171294838Szbb * unmask specific interrupts for a given group
172294838Szbb */
173294838Szbbvoid al_iofic_unmask(void __iomem *regs_base, int group, uint32_t mask)
174294838Szbb{
175294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
176294838Szbb
177294838Szbb	al_assert(regs_base);
178294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
179294838Szbb
180294838Szbb	/*
181294838Szbb	 * use the mask clear register, no need to read the mask register
182294838Szbb	 * itself. write 0 to unmask, 1 has no effect
183294838Szbb	 */
184294838Szbb	al_reg_write32_relaxed(&regs->ctrl[group].int_mask_clear_grp, ~mask);
185294838Szbb}
186294838Szbb
187294838Szbb/*
188294838Szbb * mask specific interrupts for a given group
189294838Szbb */
190294838Szbbvoid al_iofic_mask(void __iomem *regs_base, int group, uint32_t mask)
191294838Szbb{
192294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
193294838Szbb	uint32_t reg;
194294838Szbb
195294838Szbb	al_assert(regs_base);
196294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
197294838Szbb
198294838Szbb	reg = al_reg_read32(&regs->ctrl[group].int_mask_grp);
199294838Szbb
200294838Szbb	al_reg_write32(&regs->ctrl[group].int_mask_grp, reg | mask);
201294838Szbb}
202294838Szbb
203294838Szbb/*
204294838Szbb * read the mask for a given group
205294838Szbb */
206294838Szbbuint32_t al_iofic_read_mask(void __iomem *regs_base, int group)
207294838Szbb{
208294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
209294838Szbb
210294838Szbb	al_assert(regs_base);
211294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
212294838Szbb
213294838Szbb	return al_reg_read32(&regs->ctrl[group].int_mask_grp);
214294838Szbb}
215294838Szbb
216294838Szbb/*
217294838Szbb * read interrupt cause register for a given group
218294838Szbb */
219294838Szbbuint32_t al_iofic_read_cause(void __iomem *regs_base, int group)
220294838Szbb{
221294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
222294838Szbb
223294838Szbb	al_assert(regs_base);
224294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
225294838Szbb
226294838Szbb	return al_reg_read32(&regs->ctrl[group].int_cause_grp);
227294838Szbb}
228294838Szbb
229294838Szbb/*
230294838Szbb * clear bits in the interrupt cause register for a given group
231294838Szbb */
232294838Szbbvoid al_iofic_clear_cause(void __iomem *regs_base, int group, uint32_t mask)
233294838Szbb{
234294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
235294838Szbb
236294838Szbb	al_assert(regs_base);
237294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
238294838Szbb
239294838Szbb	/* inverse mask, writing 1 has no effect */
240294838Szbb	al_reg_write32(&regs->ctrl[group].int_cause_grp, ~mask);
241294838Szbb}
242294838Szbb
243294838Szbb/*
244294838Szbb * Set the cause register for a given group
245294838Szbb */
246294838Szbbvoid al_iofic_set_cause(void __iomem *regs_base, int group, uint32_t mask)
247294838Szbb{
248294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
249294838Szbb
250294838Szbb	al_assert(regs_base);
251294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
252294838Szbb
253294838Szbb	al_reg_write32(&regs->ctrl[group].int_cause_set_grp, mask);
254294838Szbb}
255294838Szbb
256294838Szbb
257294838Szbb/*
258294838Szbb * unmask specific interrupts from aborting the udma a given group
259294838Szbb */
260294838Szbbvoid al_iofic_abort_mask(void __iomem *regs_base, int group, uint32_t mask)
261294838Szbb{
262294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
263294838Szbb
264294838Szbb	al_assert(regs_base);
265294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
266294838Szbb
267294838Szbb	al_reg_write32(&regs->ctrl[group].int_abort_msk_grp, mask);
268294838Szbb
269294838Szbb}
270294838Szbb
271294838Szbb/*
272294838Szbb * trigger all interrupts that are waiting for moderation timers to expire
273294838Szbb */
274294838Szbbvoid al_iofic_interrupt_moderation_reset(void __iomem *regs_base, int group)
275294838Szbb{
276294838Szbb	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
277294838Szbb	uint32_t reg = 0;
278294838Szbb
279294838Szbb	al_assert(regs_base);
280294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
281294838Szbb
282294838Szbb	al_assert(regs_base);
283294838Szbb	al_assert(group < AL_IOFIC_MAX_GROUPS);
284294838Szbb
285294838Szbb	reg = al_reg_read32(&regs->ctrl[group].int_control_grp);
286294838Szbb	reg |= INT_CONTROL_GRP_MOD_RST;
287294838Szbb
288294838Szbb	al_reg_write32(&regs->ctrl[group].int_control_grp, reg);
289294838Szbb}
290294838Szbb
291294838Szbb/** @} end of interrupt controller group */
292