Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2017 Imagination Technologies * Author: Paul Burton <paul.burton@mips.com> */ #ifndef __MIPS_ASM_MIPS_CPS_H__ # error Please include asm/mips-cps.h rather than asm/mips-gic.h #endif #ifndef __MIPS_ASM_MIPS_GIC_H__ #define __MIPS_ASM_MIPS_GIC_H__ #include <linux/bitops.h> /* The base address of the GIC registers */ extern void __iomem *mips_gic_base; /* Offsets from the GIC base address to various control blocks */ #define MIPS_GIC_SHARED_OFS 0x00000 #define MIPS_GIC_SHARED_SZ 0x08000 #define MIPS_GIC_LOCAL_OFS 0x08000 #define MIPS_GIC_LOCAL_SZ 0x04000 #define MIPS_GIC_REDIR_OFS 0x0c000 #define MIPS_GIC_REDIR_SZ 0x04000 #define MIPS_GIC_USER_OFS 0x10000 #define MIPS_GIC_USER_SZ 0x10000 /* For read-only shared registers */ #define GIC_ACCESSOR_RO(sz, off, name) \ CPS_ACCESSOR_RO(gic, sz, MIPS_GIC_SHARED_OFS + off, name) /* For read-write shared registers */ #define GIC_ACCESSOR_RW(sz, off, name) \ CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_SHARED_OFS + off, name) /* For read-only local registers */ #define GIC_VX_ACCESSOR_RO(sz, off, name) \ CPS_ACCESSOR_RO(gic, sz, MIPS_GIC_LOCAL_OFS + off, vl_##name) \ CPS_ACCESSOR_RO(gic, sz, MIPS_GIC_REDIR_OFS + off, vo_##name) /* For read-write local registers */ #define GIC_VX_ACCESSOR_RW(sz, off, name) \ CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_LOCAL_OFS + off, vl_##name) \ CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_REDIR_OFS + off, vo_##name) /* For read-only shared per-interrupt registers */ #define GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ static inline void __iomem *addr_gic_##name(unsigned int intr) \ { \ return mips_gic_base + (off) + (intr * (stride)); \ } \ \ static inline unsigned int read_gic_##name(unsigned int intr) \ { \ BUILD_BUG_ON(sz != 32); \ return __raw_readl(addr_gic_##name(intr)); \ } /* For read-write shared per-interrupt registers */ #define GIC_ACCESSOR_RW_INTR_REG(sz, off, stride, name) \ GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ \ static inline void write_gic_##name(unsigned int intr, \ unsigned int val) \ { \ BUILD_BUG_ON(sz != 32); \ __raw_writel(val, addr_gic_##name(intr)); \ } /* For read-only local per-interrupt registers */ #define GIC_VX_ACCESSOR_RO_INTR_REG(sz, off, stride, name) \ GIC_ACCESSOR_RO_INTR_REG(sz, MIPS_GIC_LOCAL_OFS + off, \ stride, vl_##name) \ GIC_ACCESSOR_RO_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off, \ stride, vo_##name) /* For read-write local per-interrupt registers */ #define GIC_VX_ACCESSOR_RW_INTR_REG(sz, off, stride, name) \ GIC_ACCESSOR_RW_INTR_REG(sz, MIPS_GIC_LOCAL_OFS + off, \ stride, vl_##name) \ GIC_ACCESSOR_RW_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off, \ stride, vo_##name) /* For read-only shared bit-per-interrupt registers */ #define GIC_ACCESSOR_RO_INTR_BIT(off, name) \ static inline void __iomem *addr_gic_##name(void) \ { \ return mips_gic_base + (off); \ } \ \ static inline unsigned int read_gic_##name(unsigned int intr) \ { \ void __iomem *addr = addr_gic_##name(); \ unsigned int val; \ \ if (mips_cm_is64) { \ addr += (intr / 64) * sizeof(uint64_t); \ val = __raw_readq(addr) >> intr % 64; \ } else { \ addr += (intr / 32) * sizeof(uint32_t); \ val = __raw_readl(addr) >> intr % 32; \ } \ \ return val & 0x1; \ } /* For read-write shared bit-per-interrupt registers */ #define GIC_ACCESSOR_RW_INTR_BIT(off, name) \ GIC_ACCESSOR_RO_INTR_BIT(off, name) \ \ static inline void write_gic_##name(unsigned int intr) \ { \ void __iomem *addr = addr_gic_##name(); \ \ if (mips_cm_is64) { \ addr += (intr / 64) * sizeof(uint64_t); \ __raw_writeq(BIT(intr % 64), addr); \ } else { \ addr += (intr / 32) * sizeof(uint32_t); \ __raw_writel(BIT(intr % 32), addr); \ } \ } \ \ static inline void change_gic_##name(unsigned int intr, \ unsigned int val) \ { \ void __iomem *addr = addr_gic_##name(); \ \ if (mips_cm_is64) { \ uint64_t _val; \ \ addr += (intr / 64) * sizeof(uint64_t); \ _val = __raw_readq(addr); \ _val &= ~BIT_ULL(intr % 64); \ _val |= (uint64_t)val << (intr % 64); \ __raw_writeq(_val, addr); \ } else { \ uint32_t _val; \ \ addr += (intr / 32) * sizeof(uint32_t); \ _val = __raw_readl(addr); \ _val &= ~BIT(intr % 32); \ _val |= val << (intr % 32); \ __raw_writel(_val, addr); \ } \ } /* For read-only local bit-per-interrupt registers */ #define GIC_VX_ACCESSOR_RO_INTR_BIT(sz, off, name) \ GIC_ACCESSOR_RO_INTR_BIT(sz, MIPS_GIC_LOCAL_OFS + off, \ vl_##name) \ GIC_ACCESSOR_RO_INTR_BIT(sz, MIPS_GIC_REDIR_OFS + off, \ vo_##name) /* For read-write local bit-per-interrupt registers */ #define GIC_VX_ACCESSOR_RW_INTR_BIT(sz, off, name) \ GIC_ACCESSOR_RW_INTR_BIT(sz, MIPS_GIC_LOCAL_OFS + off, \ vl_##name) \ GIC_ACCESSOR_RW_INTR_BIT(sz, MIPS_GIC_REDIR_OFS + off, \ vo_##name) /* GIC_SH_CONFIG - Information about the GIC configuration */ GIC_ACCESSOR_RW(32, 0x000, config) #define GIC_CONFIG_COUNTSTOP BIT(28) #define GIC_CONFIG_COUNTBITS GENMASK(27, 24) #define GIC_CONFIG_NUMINTERRUPTS GENMASK(23, 16) #define GIC_CONFIG_PVPS GENMASK(6, 0) /* GIC_SH_COUNTER - Shared global counter value */ GIC_ACCESSOR_RW(64, 0x010, counter) GIC_ACCESSOR_RW(32, 0x010, counter_32l) GIC_ACCESSOR_RW(32, 0x014, counter_32h) /* GIC_SH_POL_* - Configures interrupt polarity */ GIC_ACCESSOR_RW_INTR_BIT(0x100, pol) #define GIC_POL_ACTIVE_LOW 0 /* when level triggered */ #define GIC_POL_ACTIVE_HIGH 1 /* when level triggered */ #define GIC_POL_FALLING_EDGE 0 /* when single-edge triggered */ #define GIC_POL_RISING_EDGE 1 /* when single-edge triggered */ /* GIC_SH_TRIG_* - Configures interrupts to be edge or level triggered */ GIC_ACCESSOR_RW_INTR_BIT(0x180, trig) #define GIC_TRIG_LEVEL 0 #define GIC_TRIG_EDGE 1 /* GIC_SH_DUAL_* - Configures whether interrupts trigger on both edges */ GIC_ACCESSOR_RW_INTR_BIT(0x200, dual) #define GIC_DUAL_SINGLE 0 /* when edge-triggered */ #define GIC_DUAL_DUAL 1 /* when edge-triggered */ /* GIC_SH_WEDGE - Write an 'edge', ie. trigger an interrupt */ GIC_ACCESSOR_RW(32, 0x280, wedge) #define GIC_WEDGE_RW BIT(31) #define GIC_WEDGE_INTR GENMASK(7, 0) /* GIC_SH_RMASK_* - Reset/clear shared interrupt mask bits */ GIC_ACCESSOR_RW_INTR_BIT(0x300, rmask) /* GIC_SH_SMASK_* - Set shared interrupt mask bits */ GIC_ACCESSOR_RW_INTR_BIT(0x380, smask) /* GIC_SH_MASK_* - Read the current shared interrupt mask */ GIC_ACCESSOR_RO_INTR_BIT(0x400, mask) /* GIC_SH_PEND_* - Read currently pending shared interrupts */ GIC_ACCESSOR_RO_INTR_BIT(0x480, pend) /* GIC_SH_MAPx_PIN - Map shared interrupts to a particular CPU pin */ GIC_ACCESSOR_RW_INTR_REG(32, 0x500, 0x4, map_pin) #define GIC_MAP_PIN_MAP_TO_PIN BIT(31) #define GIC_MAP_PIN_MAP_TO_NMI BIT(30) #define GIC_MAP_PIN_MAP GENMASK(5, 0) /* GIC_SH_MAPx_VP - Map shared interrupts to a particular Virtual Processor */ GIC_ACCESSOR_RW_INTR_REG(32, 0x2000, 0x20, map_vp) /* GIC_Vx_CTL - VP-level interrupt control */ GIC_VX_ACCESSOR_RW(32, 0x000, ctl) #define GIC_VX_CTL_FDC_ROUTABLE BIT(4) #define GIC_VX_CTL_SWINT_ROUTABLE BIT(3) #define GIC_VX_CTL_PERFCNT_ROUTABLE BIT(2) #define GIC_VX_CTL_TIMER_ROUTABLE BIT(1) #define GIC_VX_CTL_EIC BIT(0) /* GIC_Vx_PEND - Read currently pending local interrupts */ GIC_VX_ACCESSOR_RO(32, 0x004, pend) /* GIC_Vx_MASK - Read the current local interrupt mask */ GIC_VX_ACCESSOR_RO(32, 0x008, mask) /* GIC_Vx_RMASK - Reset/clear local interrupt mask bits */ GIC_VX_ACCESSOR_RW(32, 0x00c, rmask) /* GIC_Vx_SMASK - Set local interrupt mask bits */ GIC_VX_ACCESSOR_RW(32, 0x010, smask) /* GIC_Vx_*_MAP - Route local interrupts to the desired pins */ GIC_VX_ACCESSOR_RW_INTR_REG(32, 0x040, 0x4, map) /* GIC_Vx_WD_MAP - Route the local watchdog timer interrupt */ GIC_VX_ACCESSOR_RW(32, 0x040, wd_map) /* GIC_Vx_COMPARE_MAP - Route the local count/compare interrupt */ GIC_VX_ACCESSOR_RW(32, 0x044, compare_map) /* GIC_Vx_TIMER_MAP - Route the local CPU timer (cp0 count/compare) interrupt */ GIC_VX_ACCESSOR_RW(32, 0x048, timer_map) /* GIC_Vx_FDC_MAP - Route the local fast debug channel interrupt */ GIC_VX_ACCESSOR_RW(32, 0x04c, fdc_map) /* GIC_Vx_PERFCTR_MAP - Route the local performance counter interrupt */ GIC_VX_ACCESSOR_RW(32, 0x050, perfctr_map) /* GIC_Vx_SWINT0_MAP - Route the local software interrupt 0 */ GIC_VX_ACCESSOR_RW(32, 0x054, swint0_map) /* GIC_Vx_SWINT1_MAP - Route the local software interrupt 1 */ GIC_VX_ACCESSOR_RW(32, 0x058, swint1_map) /* GIC_Vx_OTHER - Configure access to other Virtual Processor registers */ GIC_VX_ACCESSOR_RW(32, 0x080, other) #define GIC_VX_OTHER_VPNUM GENMASK(5, 0) /* GIC_Vx_IDENT - Retrieve the local Virtual Processor's ID */ GIC_VX_ACCESSOR_RO(32, 0x088, ident) #define GIC_VX_IDENT_VPNUM GENMASK(5, 0) /* GIC_Vx_COMPARE - Value to compare with GIC_SH_COUNTER */ GIC_VX_ACCESSOR_RW(64, 0x0a0, compare) /* GIC_Vx_EIC_SHADOW_SET_BASE - Set shadow register set for each interrupt */ GIC_VX_ACCESSOR_RW_INTR_REG(32, 0x100, 0x4, eic_shadow_set) /** * enum mips_gic_local_interrupt - GIC local interrupts * @GIC_LOCAL_INT_WD: GIC watchdog timer interrupt * @GIC_LOCAL_INT_COMPARE: GIC count/compare interrupt * @GIC_LOCAL_INT_TIMER: CP0 count/compare interrupt * @GIC_LOCAL_INT_PERFCTR: Performance counter interrupt * @GIC_LOCAL_INT_SWINT0: Software interrupt 0 * @GIC_LOCAL_INT_SWINT1: Software interrupt 1 * @GIC_LOCAL_INT_FDC: Fast debug channel interrupt * @GIC_NUM_LOCAL_INTRS: The number of local interrupts * * Enumerates interrupts provided by the GIC that are local to a VP. */ enum mips_gic_local_interrupt { GIC_LOCAL_INT_WD, GIC_LOCAL_INT_COMPARE, GIC_LOCAL_INT_TIMER, GIC_LOCAL_INT_PERFCTR, GIC_LOCAL_INT_SWINT0, GIC_LOCAL_INT_SWINT1, GIC_LOCAL_INT_FDC, GIC_NUM_LOCAL_INTRS }; /** * mips_gic_present() - Determine whether a GIC is present * * Determines whether a MIPS Global Interrupt Controller (GIC) is present in * the system that the kernel is running on. * * Return true if a GIC is present, else false. */ static inline bool mips_gic_present(void) { return IS_ENABLED(CONFIG_MIPS_GIC) && mips_gic_base; } /** * mips_gic_vx_map_reg() - Return GIC_Vx_<intr>_MAP register offset * @intr: A GIC local interrupt * * Determine the index of the GIC_VL_<intr>_MAP or GIC_VO_<intr>_MAP register * within the block of GIC map registers. This is almost the same as the order * of interrupts in the pending & mask registers, as used by enum * mips_gic_local_interrupt, but moves the FDC interrupt & thus offsets the * interrupts after it... * * Return: The map register index corresponding to @intr. * * The return value is suitable for use with the (read|write)_gic_v[lo]_map * accessor functions. */ static inline unsigned int mips_gic_vx_map_reg(enum mips_gic_local_interrupt intr) { /* WD, Compare & Timer are 1:1 */ if (intr <= GIC_LOCAL_INT_TIMER) return intr; /* FDC moves to after Timer... */ if (intr == GIC_LOCAL_INT_FDC) return GIC_LOCAL_INT_TIMER + 1; /* As a result everything else is offset by 1 */ return intr + 1; } /** * gic_get_c0_compare_int() - Return cp0 count/compare interrupt virq * * Determine the virq number to use for the coprocessor 0 count/compare * interrupt, which may be routed via the GIC. * * Returns the virq number or a negative error number. */ extern int gic_get_c0_compare_int(void); /** * gic_get_c0_perfcount_int() - Return performance counter interrupt virq * * Determine the virq number to use for CPU performance counter interrupts, * which may be routed via the GIC. * * Returns the virq number or a negative error number. */ extern int gic_get_c0_perfcount_int(void); /** * gic_get_c0_fdc_int() - Return fast debug channel interrupt virq * * Determine the virq number to use for fast debug channel (FDC) interrupts, * which may be routed via the GIC. * * Returns the virq number or a negative error number. */ extern int gic_get_c0_fdc_int(void); #endif /* __MIPS_ASM_MIPS_CPS_H__ */ |