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(®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 */ 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 */ 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 */ 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 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(®s->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 ®s->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(®s->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(®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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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