xref: /freebsd/sys/contrib/alpine-hal/al_hal_iofic.c (revision d002f039aeb370370cd2cba63ad55cc4cf16c932)
149b49cdaSZbigniew Bodek /*-
249b49cdaSZbigniew Bodek *******************************************************************************
349b49cdaSZbigniew Bodek Copyright (C) 2015 Annapurna Labs Ltd.
449b49cdaSZbigniew Bodek 
549b49cdaSZbigniew Bodek This file may be licensed under the terms of the Annapurna Labs Commercial
649b49cdaSZbigniew Bodek License Agreement.
749b49cdaSZbigniew Bodek 
849b49cdaSZbigniew Bodek Alternatively, this file can be distributed under the terms of the GNU General
949b49cdaSZbigniew Bodek Public License V2 as published by the Free Software Foundation and can be
1049b49cdaSZbigniew Bodek found at http://www.gnu.org/licenses/gpl-2.0.html
1149b49cdaSZbigniew Bodek 
1249b49cdaSZbigniew Bodek Alternatively, redistribution and use in source and binary forms, with or
1349b49cdaSZbigniew Bodek without modification, are permitted provided that the following conditions are
1449b49cdaSZbigniew Bodek met:
1549b49cdaSZbigniew Bodek 
1649b49cdaSZbigniew Bodek     *     Redistributions of source code must retain the above copyright notice,
1749b49cdaSZbigniew Bodek this list of conditions and the following disclaimer.
1849b49cdaSZbigniew Bodek 
1949b49cdaSZbigniew Bodek     *     Redistributions in binary form must reproduce the above copyright
2049b49cdaSZbigniew Bodek notice, this list of conditions and the following disclaimer in
2149b49cdaSZbigniew Bodek the documentation and/or other materials provided with the
2249b49cdaSZbigniew Bodek distribution.
2349b49cdaSZbigniew Bodek 
2449b49cdaSZbigniew Bodek THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2549b49cdaSZbigniew Bodek ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2649b49cdaSZbigniew Bodek WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2749b49cdaSZbigniew Bodek DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2849b49cdaSZbigniew Bodek ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2949b49cdaSZbigniew Bodek (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3049b49cdaSZbigniew Bodek LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
3149b49cdaSZbigniew Bodek ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3249b49cdaSZbigniew Bodek (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3349b49cdaSZbigniew Bodek SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3449b49cdaSZbigniew Bodek 
3549b49cdaSZbigniew Bodek *******************************************************************************/
3649b49cdaSZbigniew Bodek 
3749b49cdaSZbigniew Bodek /**
3849b49cdaSZbigniew Bodek  *  @{
3949b49cdaSZbigniew Bodek  * @file   al_hal_iofic.c
4049b49cdaSZbigniew Bodek  *
4149b49cdaSZbigniew Bodek  * @brief  interrupt controller hal
4249b49cdaSZbigniew Bodek  *
4349b49cdaSZbigniew Bodek  */
4449b49cdaSZbigniew Bodek 
4549b49cdaSZbigniew Bodek #include "al_hal_iofic.h"
4649b49cdaSZbigniew Bodek #include "al_hal_iofic_regs.h"
4749b49cdaSZbigniew Bodek 
4849b49cdaSZbigniew Bodek /*
4949b49cdaSZbigniew Bodek  * configure the interrupt registers, interrupts will are kept masked
5049b49cdaSZbigniew Bodek  */
al_iofic_config(void __iomem * regs_base,int group,uint32_t flags)5149b49cdaSZbigniew Bodek int al_iofic_config(void __iomem *regs_base, int group, uint32_t flags)
5249b49cdaSZbigniew Bodek {
5349b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
5449b49cdaSZbigniew Bodek 
5549b49cdaSZbigniew Bodek 	al_assert(regs_base);
5649b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
5749b49cdaSZbigniew Bodek 
5849b49cdaSZbigniew Bodek 	al_reg_write32(&regs->ctrl[group].int_control_grp, flags);
5949b49cdaSZbigniew Bodek 
6049b49cdaSZbigniew Bodek 	return 0;
6149b49cdaSZbigniew Bodek }
6249b49cdaSZbigniew Bodek 
6349b49cdaSZbigniew Bodek /*
6449b49cdaSZbigniew Bodek  * configure the moderation timer resolution for a given group
6549b49cdaSZbigniew Bodek  */
al_iofic_moder_res_config(void __iomem * regs_base,int group,uint8_t resolution)6649b49cdaSZbigniew Bodek int al_iofic_moder_res_config(void __iomem *regs_base, int group,
6749b49cdaSZbigniew Bodek 			     uint8_t resolution)
6849b49cdaSZbigniew Bodek 
6949b49cdaSZbigniew Bodek {
7049b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
7149b49cdaSZbigniew Bodek 	uint32_t reg;
7249b49cdaSZbigniew Bodek 
7349b49cdaSZbigniew Bodek 	al_assert(regs_base);
7449b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
7549b49cdaSZbigniew Bodek 
7649b49cdaSZbigniew Bodek 	reg = al_reg_read32(&regs->ctrl[group].int_control_grp);
7749b49cdaSZbigniew Bodek 	AL_REG_FIELD_SET(reg,
7849b49cdaSZbigniew Bodek 			 INT_CONTROL_GRP_MOD_RES_MASK,
7949b49cdaSZbigniew Bodek 			 INT_CONTROL_GRP_MOD_RES_SHIFT,
8049b49cdaSZbigniew Bodek 			 resolution);
8149b49cdaSZbigniew Bodek 	al_reg_write32(&regs->ctrl[group].int_control_grp, reg);
8249b49cdaSZbigniew Bodek 
8349b49cdaSZbigniew Bodek 	return 0;
8449b49cdaSZbigniew Bodek }
8549b49cdaSZbigniew Bodek 
8649b49cdaSZbigniew Bodek /*
8749b49cdaSZbigniew Bodek  * configure the moderation timer interval for a given legacy interrupt group
8849b49cdaSZbigniew Bodek  */
al_iofic_legacy_moder_interval_config(void __iomem * regs_base,int group,uint8_t interval)8949b49cdaSZbigniew Bodek int al_iofic_legacy_moder_interval_config(void __iomem *regs_base, int group,
9049b49cdaSZbigniew Bodek 				     uint8_t interval)
9149b49cdaSZbigniew Bodek {
9249b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
9349b49cdaSZbigniew Bodek 	uint32_t reg;
9449b49cdaSZbigniew Bodek 
9549b49cdaSZbigniew Bodek 	al_assert(regs_base);
9649b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
9749b49cdaSZbigniew Bodek 
9849b49cdaSZbigniew Bodek 	reg = al_reg_read32(&regs->ctrl[group].int_control_grp);
9949b49cdaSZbigniew Bodek 	AL_REG_FIELD_SET(reg,
10049b49cdaSZbigniew Bodek 			 INT_CONTROL_GRP_MOD_INTV_MASK,
10149b49cdaSZbigniew Bodek 			 INT_CONTROL_GRP_MOD_INTV_SHIFT,
10249b49cdaSZbigniew Bodek 			 interval);
10349b49cdaSZbigniew Bodek 	al_reg_write32(&regs->ctrl[group].int_control_grp, reg);
10449b49cdaSZbigniew Bodek 
10549b49cdaSZbigniew Bodek 	return 0;
10649b49cdaSZbigniew Bodek }
10749b49cdaSZbigniew Bodek 
10849b49cdaSZbigniew Bodek 
10949b49cdaSZbigniew Bodek /*
11049b49cdaSZbigniew Bodek  * configure the moderation timer interval for a given msix vector.
11149b49cdaSZbigniew Bodek  */
al_iofic_msix_moder_interval_config(void __iomem * regs_base,int group,uint8_t vector,uint8_t interval)11249b49cdaSZbigniew Bodek int al_iofic_msix_moder_interval_config(void __iomem *regs_base, int group,
11349b49cdaSZbigniew Bodek 				       uint8_t vector, uint8_t interval)
11449b49cdaSZbigniew Bodek {
11549b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
11649b49cdaSZbigniew Bodek 	uint32_t reg;
11749b49cdaSZbigniew Bodek 
11849b49cdaSZbigniew Bodek 	al_assert(regs_base);
11949b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
12049b49cdaSZbigniew Bodek 
12149b49cdaSZbigniew Bodek 	reg = al_reg_read32(&regs->grp_int_mod[group][vector].grp_int_mod_reg);
12249b49cdaSZbigniew Bodek 	AL_REG_FIELD_SET(reg,
12349b49cdaSZbigniew Bodek 			 INT_MOD_INTV_MASK,
12449b49cdaSZbigniew Bodek 			 INT_MOD_INTV_SHIFT,
12549b49cdaSZbigniew Bodek 			 interval);
12649b49cdaSZbigniew Bodek 	al_reg_write32(&regs->grp_int_mod[group][vector].grp_int_mod_reg, reg);
12749b49cdaSZbigniew Bodek 
12849b49cdaSZbigniew Bodek 	return 0;
12949b49cdaSZbigniew Bodek }
13049b49cdaSZbigniew Bodek 
13149b49cdaSZbigniew Bodek /*
132*3fc36ee0SWojciech Macek  * configure the target-id attributes for a given msix vector.
13349b49cdaSZbigniew Bodek  */
al_iofic_msix_tgtid_attributes_config(void __iomem * regs_base,int group,uint8_t vector,uint32_t tgtid,uint8_t tgtid_en)134*3fc36ee0SWojciech Macek int al_iofic_msix_tgtid_attributes_config(void __iomem *regs_base, int group,
135*3fc36ee0SWojciech Macek 				       uint8_t vector, uint32_t tgtid, uint8_t tgtid_en)
13649b49cdaSZbigniew Bodek {
13749b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
13849b49cdaSZbigniew Bodek 	uint32_t reg = 0;
13949b49cdaSZbigniew Bodek 
14049b49cdaSZbigniew Bodek 	al_assert(regs_base);
14149b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
14249b49cdaSZbigniew Bodek 
14349b49cdaSZbigniew Bodek 	AL_REG_FIELD_SET(reg,
144*3fc36ee0SWojciech Macek 			 INT_MSIX_TGTID_MASK,
145*3fc36ee0SWojciech Macek 			 INT_MSIX_TGTID_SHIFT,
146*3fc36ee0SWojciech Macek 			 tgtid);
14749b49cdaSZbigniew Bodek 	AL_REG_BIT_VAL_SET(reg,
148*3fc36ee0SWojciech Macek 			 INT_MSIX_TGTID_EN_SHIFT,
149*3fc36ee0SWojciech Macek 			 tgtid_en);
15049b49cdaSZbigniew Bodek 
151*3fc36ee0SWojciech Macek 	al_reg_write32(&regs->grp_int_mod[group][vector].grp_int_tgtid_reg, reg);
15249b49cdaSZbigniew Bodek 
15349b49cdaSZbigniew Bodek 	return 0;
15449b49cdaSZbigniew Bodek }
15549b49cdaSZbigniew Bodek 
15649b49cdaSZbigniew Bodek /*
15749b49cdaSZbigniew Bodek  * return the offset of the unmask register for a given group
15849b49cdaSZbigniew Bodek  */
al_iofic_unmask_offset_get(void __iomem * regs_base,int group)15949b49cdaSZbigniew Bodek uint32_t __iomem * al_iofic_unmask_offset_get(void __iomem *regs_base, int group)
16049b49cdaSZbigniew Bodek {
16149b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
16249b49cdaSZbigniew Bodek 
16349b49cdaSZbigniew Bodek 	al_assert(regs_base);
16449b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
16549b49cdaSZbigniew Bodek 
16649b49cdaSZbigniew Bodek 	return &regs->ctrl[group].int_mask_clear_grp;
16749b49cdaSZbigniew Bodek }
16849b49cdaSZbigniew Bodek 
16949b49cdaSZbigniew Bodek 
17049b49cdaSZbigniew Bodek /*
17149b49cdaSZbigniew Bodek  * unmask specific interrupts for a given group
17249b49cdaSZbigniew Bodek  */
al_iofic_unmask(void __iomem * regs_base,int group,uint32_t mask)17349b49cdaSZbigniew Bodek void al_iofic_unmask(void __iomem *regs_base, int group, uint32_t mask)
17449b49cdaSZbigniew Bodek {
17549b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
17649b49cdaSZbigniew Bodek 
17749b49cdaSZbigniew Bodek 	al_assert(regs_base);
17849b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
17949b49cdaSZbigniew Bodek 
18049b49cdaSZbigniew Bodek 	/*
18149b49cdaSZbigniew Bodek 	 * use the mask clear register, no need to read the mask register
18249b49cdaSZbigniew Bodek 	 * itself. write 0 to unmask, 1 has no effect
18349b49cdaSZbigniew Bodek 	 */
18449b49cdaSZbigniew Bodek 	al_reg_write32_relaxed(&regs->ctrl[group].int_mask_clear_grp, ~mask);
18549b49cdaSZbigniew Bodek }
18649b49cdaSZbigniew Bodek 
18749b49cdaSZbigniew Bodek /*
18849b49cdaSZbigniew Bodek  * mask specific interrupts for a given group
18949b49cdaSZbigniew Bodek  */
al_iofic_mask(void __iomem * regs_base,int group,uint32_t mask)19049b49cdaSZbigniew Bodek void al_iofic_mask(void __iomem *regs_base, int group, uint32_t mask)
19149b49cdaSZbigniew Bodek {
19249b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
19349b49cdaSZbigniew Bodek 	uint32_t reg;
19449b49cdaSZbigniew Bodek 
19549b49cdaSZbigniew Bodek 	al_assert(regs_base);
19649b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
19749b49cdaSZbigniew Bodek 
19849b49cdaSZbigniew Bodek 	reg = al_reg_read32(&regs->ctrl[group].int_mask_grp);
19949b49cdaSZbigniew Bodek 
20049b49cdaSZbigniew Bodek 	al_reg_write32(&regs->ctrl[group].int_mask_grp, reg | mask);
20149b49cdaSZbigniew Bodek }
20249b49cdaSZbigniew Bodek 
20349b49cdaSZbigniew Bodek /*
20449b49cdaSZbigniew Bodek  * read the mask for a given group
20549b49cdaSZbigniew Bodek  */
al_iofic_read_mask(void __iomem * regs_base,int group)20649b49cdaSZbigniew Bodek uint32_t al_iofic_read_mask(void __iomem *regs_base, int group)
20749b49cdaSZbigniew Bodek {
20849b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
20949b49cdaSZbigniew Bodek 
21049b49cdaSZbigniew Bodek 	al_assert(regs_base);
21149b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
21249b49cdaSZbigniew Bodek 
21349b49cdaSZbigniew Bodek 	return al_reg_read32(&regs->ctrl[group].int_mask_grp);
21449b49cdaSZbigniew Bodek }
21549b49cdaSZbigniew Bodek 
21649b49cdaSZbigniew Bodek /*
21749b49cdaSZbigniew Bodek  * read interrupt cause register for a given group
21849b49cdaSZbigniew Bodek  */
al_iofic_read_cause(void __iomem * regs_base,int group)21949b49cdaSZbigniew Bodek uint32_t al_iofic_read_cause(void __iomem *regs_base, int group)
22049b49cdaSZbigniew Bodek {
22149b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
22249b49cdaSZbigniew Bodek 
22349b49cdaSZbigniew Bodek 	al_assert(regs_base);
22449b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
22549b49cdaSZbigniew Bodek 
22649b49cdaSZbigniew Bodek 	return al_reg_read32(&regs->ctrl[group].int_cause_grp);
22749b49cdaSZbigniew Bodek }
22849b49cdaSZbigniew Bodek 
22949b49cdaSZbigniew Bodek /*
23049b49cdaSZbigniew Bodek  * clear bits in the interrupt cause register for a given group
23149b49cdaSZbigniew Bodek  */
al_iofic_clear_cause(void __iomem * regs_base,int group,uint32_t mask)23249b49cdaSZbigniew Bodek void al_iofic_clear_cause(void __iomem *regs_base, int group, uint32_t mask)
23349b49cdaSZbigniew Bodek {
23449b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
23549b49cdaSZbigniew Bodek 
23649b49cdaSZbigniew Bodek 	al_assert(regs_base);
23749b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
23849b49cdaSZbigniew Bodek 
23949b49cdaSZbigniew Bodek 	/* inverse mask, writing 1 has no effect */
24049b49cdaSZbigniew Bodek 	al_reg_write32(&regs->ctrl[group].int_cause_grp, ~mask);
24149b49cdaSZbigniew Bodek }
24249b49cdaSZbigniew Bodek 
24349b49cdaSZbigniew Bodek /*
24449b49cdaSZbigniew Bodek  * Set the cause register for a given group
24549b49cdaSZbigniew Bodek  */
al_iofic_set_cause(void __iomem * regs_base,int group,uint32_t mask)24649b49cdaSZbigniew Bodek void al_iofic_set_cause(void __iomem *regs_base, int group, uint32_t mask)
24749b49cdaSZbigniew Bodek {
24849b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
24949b49cdaSZbigniew Bodek 
25049b49cdaSZbigniew Bodek 	al_assert(regs_base);
25149b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
25249b49cdaSZbigniew Bodek 
25349b49cdaSZbigniew Bodek 	al_reg_write32(&regs->ctrl[group].int_cause_set_grp, mask);
25449b49cdaSZbigniew Bodek }
25549b49cdaSZbigniew Bodek 
25649b49cdaSZbigniew Bodek 
25749b49cdaSZbigniew Bodek /*
25849b49cdaSZbigniew Bodek  * unmask specific interrupts from aborting the udma a given group
25949b49cdaSZbigniew Bodek  */
al_iofic_abort_mask(void __iomem * regs_base,int group,uint32_t mask)26049b49cdaSZbigniew Bodek void al_iofic_abort_mask(void __iomem *regs_base, int group, uint32_t mask)
26149b49cdaSZbigniew Bodek {
26249b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
26349b49cdaSZbigniew Bodek 
26449b49cdaSZbigniew Bodek 	al_assert(regs_base);
26549b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
26649b49cdaSZbigniew Bodek 
26749b49cdaSZbigniew Bodek 	al_reg_write32(&regs->ctrl[group].int_abort_msk_grp, mask);
26849b49cdaSZbigniew Bodek 
26949b49cdaSZbigniew Bodek }
27049b49cdaSZbigniew Bodek 
27149b49cdaSZbigniew Bodek /*
27249b49cdaSZbigniew Bodek  * trigger all interrupts that are waiting for moderation timers to expire
27349b49cdaSZbigniew Bodek  */
al_iofic_interrupt_moderation_reset(void __iomem * regs_base,int group)27449b49cdaSZbigniew Bodek void al_iofic_interrupt_moderation_reset(void __iomem *regs_base, int group)
27549b49cdaSZbigniew Bodek {
27649b49cdaSZbigniew Bodek 	struct al_iofic_regs __iomem *regs = (struct al_iofic_regs __iomem *)(regs_base);
27749b49cdaSZbigniew Bodek 	uint32_t reg = 0;
27849b49cdaSZbigniew Bodek 
27949b49cdaSZbigniew Bodek 	al_assert(regs_base);
28049b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
28149b49cdaSZbigniew Bodek 
28249b49cdaSZbigniew Bodek 	al_assert(regs_base);
28349b49cdaSZbigniew Bodek 	al_assert(group < AL_IOFIC_MAX_GROUPS);
28449b49cdaSZbigniew Bodek 
28549b49cdaSZbigniew Bodek 	reg = al_reg_read32(&regs->ctrl[group].int_control_grp);
28649b49cdaSZbigniew Bodek 	reg |= INT_CONTROL_GRP_MOD_RST;
28749b49cdaSZbigniew Bodek 
28849b49cdaSZbigniew Bodek 	al_reg_write32(&regs->ctrl[group].int_control_grp, reg);
28949b49cdaSZbigniew Bodek }
29049b49cdaSZbigniew Bodek 
29149b49cdaSZbigniew Bodek /** @} end of interrupt controller group */
292