1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <arch_helpers.h> 8*91f16700Schasinglulu #include <common/debug.h> 9*91f16700Schasinglulu #include <drivers/arm/gic_common.h> 10*91f16700Schasinglulu #include <lib/mmio.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <mt_cirq.h> 13*91f16700Schasinglulu #include <mt_gic_v3.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu static struct cirq_events cirq_all_events = { 16*91f16700Schasinglulu .spi_start = CIRQ_SPI_START, 17*91f16700Schasinglulu }; 18*91f16700Schasinglulu static uint32_t already_cloned; 19*91f16700Schasinglulu /* 20*91f16700Schasinglulu * mt_irq_mask_restore: restore all interrupts 21*91f16700Schasinglulu * @mask: pointer to struct mtk_irq_mask for storing the original mask value. 22*91f16700Schasinglulu * Return 0 for success; return negative values for failure. 23*91f16700Schasinglulu * (This is ONLY used for the idle current measurement by the factory mode.) 24*91f16700Schasinglulu */ 25*91f16700Schasinglulu int mt_irq_mask_restore(struct mtk_irq_mask *mask) 26*91f16700Schasinglulu { 27*91f16700Schasinglulu if (mask == NULL) { 28*91f16700Schasinglulu return -1; 29*91f16700Schasinglulu } 30*91f16700Schasinglulu if (mask->header != IRQ_MASK_HEADER) { 31*91f16700Schasinglulu return -1; 32*91f16700Schasinglulu } 33*91f16700Schasinglulu if (mask->footer != IRQ_MASK_FOOTER) { 34*91f16700Schasinglulu return -1; 35*91f16700Schasinglulu } 36*91f16700Schasinglulu 37*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x4), 38*91f16700Schasinglulu mask->mask1); 39*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x8), 40*91f16700Schasinglulu mask->mask2); 41*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0xc), 42*91f16700Schasinglulu mask->mask3); 43*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x10), 44*91f16700Schasinglulu mask->mask4); 45*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x14), 46*91f16700Schasinglulu mask->mask5); 47*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x18), 48*91f16700Schasinglulu mask->mask6); 49*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x1c), 50*91f16700Schasinglulu mask->mask7); 51*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x20), 52*91f16700Schasinglulu mask->mask8); 53*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x24), 54*91f16700Schasinglulu mask->mask9); 55*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x28), 56*91f16700Schasinglulu mask->mask10); 57*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x2c), 58*91f16700Schasinglulu mask->mask11); 59*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x30), 60*91f16700Schasinglulu mask->mask12); 61*91f16700Schasinglulu /* make sure dist changes happen */ 62*91f16700Schasinglulu dsb(); 63*91f16700Schasinglulu 64*91f16700Schasinglulu return 0; 65*91f16700Schasinglulu } 66*91f16700Schasinglulu 67*91f16700Schasinglulu /* 68*91f16700Schasinglulu * mt_irq_mask_all: disable all interrupts 69*91f16700Schasinglulu * @mask: pointer to struct mtk_irq_mask for storing the original mask value. 70*91f16700Schasinglulu * Return 0 for success; return negative values for failure. 71*91f16700Schasinglulu * (This is ONLY used for the idle current measurement by the factory mode.) 72*91f16700Schasinglulu */ 73*91f16700Schasinglulu int mt_irq_mask_all(struct mtk_irq_mask *mask) 74*91f16700Schasinglulu { 75*91f16700Schasinglulu if (mask != NULL) { 76*91f16700Schasinglulu /* for SPI */ 77*91f16700Schasinglulu mask->mask1 = mmio_read_32((BASE_GICD_BASE + 78*91f16700Schasinglulu GICD_ISENABLER + 0x4)); 79*91f16700Schasinglulu mask->mask2 = mmio_read_32((BASE_GICD_BASE + 80*91f16700Schasinglulu GICD_ISENABLER + 0x8)); 81*91f16700Schasinglulu mask->mask3 = mmio_read_32((BASE_GICD_BASE + 82*91f16700Schasinglulu GICD_ISENABLER + 0xc)); 83*91f16700Schasinglulu mask->mask4 = mmio_read_32((BASE_GICD_BASE + 84*91f16700Schasinglulu GICD_ISENABLER + 0x10)); 85*91f16700Schasinglulu mask->mask5 = mmio_read_32((BASE_GICD_BASE + 86*91f16700Schasinglulu GICD_ISENABLER + 0x14)); 87*91f16700Schasinglulu mask->mask6 = mmio_read_32((BASE_GICD_BASE + 88*91f16700Schasinglulu GICD_ISENABLER + 0x18)); 89*91f16700Schasinglulu mask->mask7 = mmio_read_32((BASE_GICD_BASE + 90*91f16700Schasinglulu GICD_ISENABLER + 0x1c)); 91*91f16700Schasinglulu mask->mask8 = mmio_read_32((BASE_GICD_BASE + 92*91f16700Schasinglulu GICD_ISENABLER + 0x20)); 93*91f16700Schasinglulu mask->mask9 = mmio_read_32((BASE_GICD_BASE + 94*91f16700Schasinglulu GICD_ISENABLER + 0x24)); 95*91f16700Schasinglulu mask->mask10 = mmio_read_32((BASE_GICD_BASE + 96*91f16700Schasinglulu GICD_ISENABLER + 0x28)); 97*91f16700Schasinglulu mask->mask11 = mmio_read_32((BASE_GICD_BASE + 98*91f16700Schasinglulu GICD_ISENABLER + 0x2c)); 99*91f16700Schasinglulu mask->mask12 = mmio_read_32((BASE_GICD_BASE + 100*91f16700Schasinglulu GICD_ISENABLER + 0x30)); 101*91f16700Schasinglulu 102*91f16700Schasinglulu /* for SPI */ 103*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x4), 104*91f16700Schasinglulu 0xFFFFFFFF); 105*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x8), 106*91f16700Schasinglulu 0xFFFFFFFF); 107*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0xC), 108*91f16700Schasinglulu 0xFFFFFFFF); 109*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x10), 110*91f16700Schasinglulu 0xFFFFFFFF); 111*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x14), 112*91f16700Schasinglulu 0xFFFFFFFF); 113*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x18), 114*91f16700Schasinglulu 0xFFFFFFFF); 115*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x1C), 116*91f16700Schasinglulu 0xFFFFFFFF); 117*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x20), 118*91f16700Schasinglulu 0xFFFFFFFF); 119*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x24), 120*91f16700Schasinglulu 0xFFFFFFFF); 121*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x28), 122*91f16700Schasinglulu 0xFFFFFFFF); 123*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x2c), 124*91f16700Schasinglulu 0xFFFFFFFF); 125*91f16700Schasinglulu mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x30), 126*91f16700Schasinglulu 0xFFFFFFFF); 127*91f16700Schasinglulu /* make sure distributor changes happen */ 128*91f16700Schasinglulu dsb(); 129*91f16700Schasinglulu 130*91f16700Schasinglulu mask->header = IRQ_MASK_HEADER; 131*91f16700Schasinglulu mask->footer = IRQ_MASK_FOOTER; 132*91f16700Schasinglulu 133*91f16700Schasinglulu return 0; 134*91f16700Schasinglulu } else { 135*91f16700Schasinglulu return -1; 136*91f16700Schasinglulu } 137*91f16700Schasinglulu } 138*91f16700Schasinglulu 139*91f16700Schasinglulu static uint32_t mt_irq_get_pol(uint32_t irq) 140*91f16700Schasinglulu { 141*91f16700Schasinglulu #ifdef CIRQ_WITH_POLARITY 142*91f16700Schasinglulu uint32_t reg; 143*91f16700Schasinglulu uint32_t base = INT_POL_CTL0; 144*91f16700Schasinglulu 145*91f16700Schasinglulu if (irq < 32U) { 146*91f16700Schasinglulu return 0; 147*91f16700Schasinglulu } 148*91f16700Schasinglulu 149*91f16700Schasinglulu reg = ((irq - 32U) / 32U); 150*91f16700Schasinglulu 151*91f16700Schasinglulu return mmio_read_32(base + reg * 4U); 152*91f16700Schasinglulu #else 153*91f16700Schasinglulu return 0; 154*91f16700Schasinglulu #endif 155*91f16700Schasinglulu } 156*91f16700Schasinglulu 157*91f16700Schasinglulu unsigned int mt_irq_get_sens(unsigned int irq) 158*91f16700Schasinglulu { 159*91f16700Schasinglulu unsigned int config; 160*91f16700Schasinglulu 161*91f16700Schasinglulu /* 162*91f16700Schasinglulu * 2'b10 edge 163*91f16700Schasinglulu * 2'b01 level 164*91f16700Schasinglulu */ 165*91f16700Schasinglulu config = mmio_read_32(MT_GIC_BASE + GICD_ICFGR + (irq / 16U) * 4U); 166*91f16700Schasinglulu config = (config >> (irq % 16U) * 2U) & 0x3; 167*91f16700Schasinglulu 168*91f16700Schasinglulu return config; 169*91f16700Schasinglulu } 170*91f16700Schasinglulu 171*91f16700Schasinglulu static void collect_all_wakeup_events(void) 172*91f16700Schasinglulu { 173*91f16700Schasinglulu unsigned int i; 174*91f16700Schasinglulu uint32_t gic_irq; 175*91f16700Schasinglulu uint32_t cirq; 176*91f16700Schasinglulu uint32_t cirq_reg; 177*91f16700Schasinglulu uint32_t cirq_offset; 178*91f16700Schasinglulu uint32_t mask; 179*91f16700Schasinglulu uint32_t pol_mask; 180*91f16700Schasinglulu uint32_t irq_offset; 181*91f16700Schasinglulu uint32_t irq_mask; 182*91f16700Schasinglulu 183*91f16700Schasinglulu if ((cirq_all_events.wakeup_events == NULL) || 184*91f16700Schasinglulu cirq_all_events.num_of_events == 0U) { 185*91f16700Schasinglulu return; 186*91f16700Schasinglulu } 187*91f16700Schasinglulu 188*91f16700Schasinglulu for (i = 0U; i < cirq_all_events.num_of_events; i++) { 189*91f16700Schasinglulu if (cirq_all_events.wakeup_events[i] > 0U) { 190*91f16700Schasinglulu gic_irq = cirq_all_events.wakeup_events[i]; 191*91f16700Schasinglulu cirq = gic_irq - cirq_all_events.spi_start - 32U; 192*91f16700Schasinglulu cirq_reg = cirq / 32U; 193*91f16700Schasinglulu cirq_offset = cirq % 32U; 194*91f16700Schasinglulu mask = 0x1 << cirq_offset; 195*91f16700Schasinglulu irq_offset = gic_irq % 32U; 196*91f16700Schasinglulu irq_mask = 0x1 << irq_offset; 197*91f16700Schasinglulu /* 198*91f16700Schasinglulu * CIRQ default masks all 199*91f16700Schasinglulu */ 200*91f16700Schasinglulu cirq_all_events.table[cirq_reg].mask |= mask; 201*91f16700Schasinglulu /* 202*91f16700Schasinglulu * CIRQ default pol is low 203*91f16700Schasinglulu */ 204*91f16700Schasinglulu pol_mask = mt_irq_get_pol( 205*91f16700Schasinglulu cirq_all_events.wakeup_events[i]) 206*91f16700Schasinglulu & irq_mask; 207*91f16700Schasinglulu /* 208*91f16700Schasinglulu * 0 means rising 209*91f16700Schasinglulu */ 210*91f16700Schasinglulu if (pol_mask == 0U) { 211*91f16700Schasinglulu cirq_all_events.table[cirq_reg].pol |= mask; 212*91f16700Schasinglulu } 213*91f16700Schasinglulu /* 214*91f16700Schasinglulu * CIRQ could monitor edge/level trigger 215*91f16700Schasinglulu * cirq register (0: edge, 1: level) 216*91f16700Schasinglulu */ 217*91f16700Schasinglulu if (mt_irq_get_sens(cirq_all_events.wakeup_events[i]) 218*91f16700Schasinglulu == SENS_EDGE) { 219*91f16700Schasinglulu cirq_all_events.table[cirq_reg].sen |= mask; 220*91f16700Schasinglulu } 221*91f16700Schasinglulu 222*91f16700Schasinglulu cirq_all_events.table[cirq_reg].used = 1U; 223*91f16700Schasinglulu cirq_all_events.table[cirq_reg].reg_num = cirq_reg; 224*91f16700Schasinglulu } 225*91f16700Schasinglulu } 226*91f16700Schasinglulu } 227*91f16700Schasinglulu 228*91f16700Schasinglulu /* 229*91f16700Schasinglulu * mt_cirq_set_pol: Set the polarity for the specified SYS_CIRQ number. 230*91f16700Schasinglulu * @cirq_num: the SYS_CIRQ number to set 231*91f16700Schasinglulu * @pol: polarity to set 232*91f16700Schasinglulu * @return: 233*91f16700Schasinglulu * 0: set pol success 234*91f16700Schasinglulu * -1: cirq num is out of range 235*91f16700Schasinglulu */ 236*91f16700Schasinglulu #ifdef CIRQ_WITH_POLARITY 237*91f16700Schasinglulu static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol) 238*91f16700Schasinglulu { 239*91f16700Schasinglulu uint32_t base; 240*91f16700Schasinglulu uint32_t bit = 1U << (cirq_num % 32U); 241*91f16700Schasinglulu 242*91f16700Schasinglulu if (cirq_num >= CIRQ_IRQ_NUM) { 243*91f16700Schasinglulu return -1; 244*91f16700Schasinglulu } 245*91f16700Schasinglulu 246*91f16700Schasinglulu if (pol == MT_CIRQ_POL_NEG) { 247*91f16700Schasinglulu base = (cirq_num / 32U) * 4U + CIRQ_POL_CLR_BASE; 248*91f16700Schasinglulu } else if (pol == MT_CIRQ_POL_POS) { 249*91f16700Schasinglulu base = (cirq_num / 32U) * 4U + CIRQ_POL_SET_BASE; 250*91f16700Schasinglulu } else { 251*91f16700Schasinglulu return -1; 252*91f16700Schasinglulu } 253*91f16700Schasinglulu 254*91f16700Schasinglulu mmio_write_32(base, bit); 255*91f16700Schasinglulu return 0; 256*91f16700Schasinglulu } 257*91f16700Schasinglulu #endif 258*91f16700Schasinglulu 259*91f16700Schasinglulu /* 260*91f16700Schasinglulu * mt_cirq_mask: Mask the specified SYS_CIRQ. 261*91f16700Schasinglulu * @cirq_num: the SYS_CIRQ number to mask 262*91f16700Schasinglulu * @return: 263*91f16700Schasinglulu * 0: mask success 264*91f16700Schasinglulu * -1: cirq num is out of range 265*91f16700Schasinglulu */ 266*91f16700Schasinglulu static int mt_cirq_mask(uint32_t cirq_num) 267*91f16700Schasinglulu { 268*91f16700Schasinglulu uint32_t bit = 1U << (cirq_num % 32U); 269*91f16700Schasinglulu 270*91f16700Schasinglulu if (cirq_num >= CIRQ_IRQ_NUM) { 271*91f16700Schasinglulu return -1; 272*91f16700Schasinglulu } 273*91f16700Schasinglulu 274*91f16700Schasinglulu mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE, bit); 275*91f16700Schasinglulu 276*91f16700Schasinglulu return 0; 277*91f16700Schasinglulu } 278*91f16700Schasinglulu 279*91f16700Schasinglulu /* 280*91f16700Schasinglulu * mt_cirq_unmask: Unmask the specified SYS_CIRQ. 281*91f16700Schasinglulu * @cirq_num: the SYS_CIRQ number to unmask 282*91f16700Schasinglulu * @return: 283*91f16700Schasinglulu * 0: umask success 284*91f16700Schasinglulu * -1: cirq num is out of range 285*91f16700Schasinglulu */ 286*91f16700Schasinglulu static int mt_cirq_unmask(uint32_t cirq_num) 287*91f16700Schasinglulu { 288*91f16700Schasinglulu uint32_t bit = 1U << (cirq_num % 32U); 289*91f16700Schasinglulu 290*91f16700Schasinglulu if (cirq_num >= CIRQ_IRQ_NUM) { 291*91f16700Schasinglulu return -1; 292*91f16700Schasinglulu } 293*91f16700Schasinglulu 294*91f16700Schasinglulu mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE, bit); 295*91f16700Schasinglulu 296*91f16700Schasinglulu return 0; 297*91f16700Schasinglulu } 298*91f16700Schasinglulu 299*91f16700Schasinglulu uint32_t mt_irq_get_en(uint32_t irq) 300*91f16700Schasinglulu { 301*91f16700Schasinglulu uint32_t addr, st, val; 302*91f16700Schasinglulu 303*91f16700Schasinglulu addr = BASE_GICD_BASE + GICD_ISENABLER + (irq / 32U) * 4U; 304*91f16700Schasinglulu st = mmio_read_32(addr); 305*91f16700Schasinglulu 306*91f16700Schasinglulu val = (st >> (irq % 32U)) & 1U; 307*91f16700Schasinglulu 308*91f16700Schasinglulu return val; 309*91f16700Schasinglulu } 310*91f16700Schasinglulu 311*91f16700Schasinglulu static void __cirq_fast_clone(void) 312*91f16700Schasinglulu { 313*91f16700Schasinglulu struct cirq_reg *reg; 314*91f16700Schasinglulu unsigned int i; 315*91f16700Schasinglulu 316*91f16700Schasinglulu for (i = 0U; i < CIRQ_REG_NUM ; ++i) { 317*91f16700Schasinglulu uint32_t cirq_bit; 318*91f16700Schasinglulu 319*91f16700Schasinglulu reg = &cirq_all_events.table[i]; 320*91f16700Schasinglulu 321*91f16700Schasinglulu if (reg->used == 0U) { 322*91f16700Schasinglulu continue; 323*91f16700Schasinglulu } 324*91f16700Schasinglulu 325*91f16700Schasinglulu mmio_write_32(CIRQ_SENS_CLR_BASE + (reg->reg_num * 4U), 326*91f16700Schasinglulu reg->sen); 327*91f16700Schasinglulu 328*91f16700Schasinglulu for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) { 329*91f16700Schasinglulu uint32_t val, cirq_id; 330*91f16700Schasinglulu uint32_t gic_id; 331*91f16700Schasinglulu #ifdef CIRQ_WITH_POLARITY 332*91f16700Schasinglulu uint32_t gic_bit, pol; 333*91f16700Schasinglulu #endif 334*91f16700Schasinglulu uint32_t en; 335*91f16700Schasinglulu 336*91f16700Schasinglulu val = ((1U << cirq_bit) & reg->mask); 337*91f16700Schasinglulu 338*91f16700Schasinglulu if (val == 0U) { 339*91f16700Schasinglulu continue; 340*91f16700Schasinglulu } 341*91f16700Schasinglulu 342*91f16700Schasinglulu cirq_id = (reg->reg_num << 5U) + cirq_bit; 343*91f16700Schasinglulu gic_id = CIRQ_TO_IRQ_NUM(cirq_id); 344*91f16700Schasinglulu #ifdef CIRQ_WITH_POLARITY 345*91f16700Schasinglulu gic_bit = (0x1U << ((gic_id - 32U) % 32U)); 346*91f16700Schasinglulu pol = mt_irq_get_pol(gic_id) & gic_bit; 347*91f16700Schasinglulu if (pol != 0U) { 348*91f16700Schasinglulu mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_NEG); 349*91f16700Schasinglulu } else { 350*91f16700Schasinglulu mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_POS); 351*91f16700Schasinglulu } 352*91f16700Schasinglulu #endif 353*91f16700Schasinglulu en = mt_irq_get_en(gic_id); 354*91f16700Schasinglulu if (en == 1U) { 355*91f16700Schasinglulu mt_cirq_unmask(cirq_id); 356*91f16700Schasinglulu } else { 357*91f16700Schasinglulu mt_cirq_mask(cirq_id); 358*91f16700Schasinglulu } 359*91f16700Schasinglulu } 360*91f16700Schasinglulu } 361*91f16700Schasinglulu } 362*91f16700Schasinglulu 363*91f16700Schasinglulu static void cirq_fast_clone(void) 364*91f16700Schasinglulu { 365*91f16700Schasinglulu if (already_cloned == 0U) { 366*91f16700Schasinglulu collect_all_wakeup_events(); 367*91f16700Schasinglulu already_cloned = 1U; 368*91f16700Schasinglulu } 369*91f16700Schasinglulu __cirq_fast_clone(); 370*91f16700Schasinglulu } 371*91f16700Schasinglulu 372*91f16700Schasinglulu void set_wakeup_sources(uint32_t *list, uint32_t num_of_events) 373*91f16700Schasinglulu { 374*91f16700Schasinglulu cirq_all_events.num_of_events = num_of_events; 375*91f16700Schasinglulu cirq_all_events.wakeup_events = list; 376*91f16700Schasinglulu } 377*91f16700Schasinglulu /* 378*91f16700Schasinglulu * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ 379*91f16700Schasinglulu */ 380*91f16700Schasinglulu void mt_cirq_clone_gic(void) 381*91f16700Schasinglulu { 382*91f16700Schasinglulu cirq_fast_clone(); 383*91f16700Schasinglulu } 384*91f16700Schasinglulu 385*91f16700Schasinglulu uint32_t mt_irq_get_pending_vec(uint32_t start_irq) 386*91f16700Schasinglulu { 387*91f16700Schasinglulu uint32_t base = 0U; 388*91f16700Schasinglulu uint32_t pending_vec = 0U; 389*91f16700Schasinglulu uint32_t reg = start_irq / 32U; 390*91f16700Schasinglulu uint32_t LSB_num, MSB_num; 391*91f16700Schasinglulu uint32_t LSB_vec, MSB_vec; 392*91f16700Schasinglulu 393*91f16700Schasinglulu base = BASE_GICD_BASE; 394*91f16700Schasinglulu 395*91f16700Schasinglulu /* if start_irq is not aligned 32, do some assembling */ 396*91f16700Schasinglulu MSB_num = start_irq % 32U; 397*91f16700Schasinglulu if (MSB_num != 0U) { 398*91f16700Schasinglulu LSB_num = 32U - MSB_num; 399*91f16700Schasinglulu LSB_vec = mmio_read_32(base + GICD_ISPENDR + 400*91f16700Schasinglulu reg * 4U) >> MSB_num; 401*91f16700Schasinglulu MSB_vec = mmio_read_32(base + GICD_ISPENDR + 402*91f16700Schasinglulu (reg + 1U) * 4U) << LSB_num; 403*91f16700Schasinglulu pending_vec = MSB_vec | LSB_vec; 404*91f16700Schasinglulu } else { 405*91f16700Schasinglulu pending_vec = mmio_read_32(base + GICD_ISPENDR + reg * 4); 406*91f16700Schasinglulu } 407*91f16700Schasinglulu 408*91f16700Schasinglulu return pending_vec; 409*91f16700Schasinglulu } 410*91f16700Schasinglulu 411*91f16700Schasinglulu static int mt_cirq_get_mask_vec(unsigned int i) 412*91f16700Schasinglulu { 413*91f16700Schasinglulu return mmio_read_32((i * 4U) + CIRQ_MASK_BASE); 414*91f16700Schasinglulu } 415*91f16700Schasinglulu 416*91f16700Schasinglulu /* 417*91f16700Schasinglulu * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ 418*91f16700Schasinglulu */ 419*91f16700Schasinglulu void mt_cirq_ack_all(void) 420*91f16700Schasinglulu { 421*91f16700Schasinglulu uint32_t ack_vec, pend_vec, mask_vec; 422*91f16700Schasinglulu unsigned int i; 423*91f16700Schasinglulu 424*91f16700Schasinglulu for (i = 0; i < CIRQ_CTRL_REG_NUM; i++) { 425*91f16700Schasinglulu /* 426*91f16700Schasinglulu * if a irq is pending & not masked, don't ack it 427*91f16700Schasinglulu * , since cirq start irq might not be 32 aligned with gic, 428*91f16700Schasinglulu * need an exotic API to get proper vector of pending irq 429*91f16700Schasinglulu */ 430*91f16700Schasinglulu pend_vec = mt_irq_get_pending_vec(CIRQ_SPI_START 431*91f16700Schasinglulu + (i + 1U) * 32U); 432*91f16700Schasinglulu mask_vec = mt_cirq_get_mask_vec(i); 433*91f16700Schasinglulu /* those should be acked are: "not (pending & not masked)", 434*91f16700Schasinglulu */ 435*91f16700Schasinglulu ack_vec = (~pend_vec) | mask_vec; 436*91f16700Schasinglulu mmio_write_32(CIRQ_ACK_BASE + (i * 4U), ack_vec); 437*91f16700Schasinglulu } 438*91f16700Schasinglulu 439*91f16700Schasinglulu /* 440*91f16700Schasinglulu * make sure all cirq setting take effect 441*91f16700Schasinglulu * before doing other things 442*91f16700Schasinglulu */ 443*91f16700Schasinglulu dsb(); 444*91f16700Schasinglulu } 445*91f16700Schasinglulu /* 446*91f16700Schasinglulu * mt_cirq_enable: Enable SYS_CIRQ 447*91f16700Schasinglulu */ 448*91f16700Schasinglulu void mt_cirq_enable(void) 449*91f16700Schasinglulu { 450*91f16700Schasinglulu uint32_t st; 451*91f16700Schasinglulu 452*91f16700Schasinglulu /* level only */ 453*91f16700Schasinglulu mt_cirq_ack_all(); 454*91f16700Schasinglulu 455*91f16700Schasinglulu st = mmio_read_32(CIRQ_CON); 456*91f16700Schasinglulu /* 457*91f16700Schasinglulu * CIRQ could monitor edge/level trigger 458*91f16700Schasinglulu */ 459*91f16700Schasinglulu st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS); 460*91f16700Schasinglulu 461*91f16700Schasinglulu mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK)); 462*91f16700Schasinglulu } 463*91f16700Schasinglulu 464*91f16700Schasinglulu /* 465*91f16700Schasinglulu * mt_cirq_disable: Disable SYS_CIRQ 466*91f16700Schasinglulu */ 467*91f16700Schasinglulu void mt_cirq_disable(void) 468*91f16700Schasinglulu { 469*91f16700Schasinglulu uint32_t st; 470*91f16700Schasinglulu 471*91f16700Schasinglulu st = mmio_read_32(CIRQ_CON); 472*91f16700Schasinglulu st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS); 473*91f16700Schasinglulu mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK)); 474*91f16700Schasinglulu } 475*91f16700Schasinglulu 476*91f16700Schasinglulu void mt_irq_unmask_for_sleep_ex(uint32_t irq) 477*91f16700Schasinglulu { 478*91f16700Schasinglulu uint32_t mask; 479*91f16700Schasinglulu 480*91f16700Schasinglulu mask = 1U << (irq % 32U); 481*91f16700Schasinglulu 482*91f16700Schasinglulu mmio_write_32(BASE_GICD_BASE + GICD_ISENABLER + 483*91f16700Schasinglulu ((irq / 32U) * 4U), mask); 484*91f16700Schasinglulu } 485*91f16700Schasinglulu 486*91f16700Schasinglulu void mt_cirq_mask_all(void) 487*91f16700Schasinglulu { 488*91f16700Schasinglulu unsigned int i; 489*91f16700Schasinglulu 490*91f16700Schasinglulu for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { 491*91f16700Schasinglulu mmio_write_32(CIRQ_MASK_SET_BASE + (i * 4U), 0xFFFFFFFF); 492*91f16700Schasinglulu } 493*91f16700Schasinglulu dsb(); 494*91f16700Schasinglulu } 495*91f16700Schasinglulu 496*91f16700Schasinglulu static void cirq_fast_sw_flush(void) 497*91f16700Schasinglulu { 498*91f16700Schasinglulu struct cirq_reg *reg; 499*91f16700Schasinglulu unsigned int i; 500*91f16700Schasinglulu 501*91f16700Schasinglulu for (i = 0U; i < CIRQ_REG_NUM ; ++i) { 502*91f16700Schasinglulu uint32_t cirq_bit; 503*91f16700Schasinglulu 504*91f16700Schasinglulu reg = &cirq_all_events.table[i]; 505*91f16700Schasinglulu 506*91f16700Schasinglulu if (reg->used == 0U) { 507*91f16700Schasinglulu continue; 508*91f16700Schasinglulu } 509*91f16700Schasinglulu 510*91f16700Schasinglulu reg->pending = mmio_read_32(CIRQ_STA_BASE + 511*91f16700Schasinglulu (reg->reg_num << 2U)); 512*91f16700Schasinglulu reg->pending &= reg->mask; 513*91f16700Schasinglulu 514*91f16700Schasinglulu for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) { 515*91f16700Schasinglulu uint32_t val, cirq_id; 516*91f16700Schasinglulu 517*91f16700Schasinglulu val = (1U << cirq_bit) & reg->pending; 518*91f16700Schasinglulu if (val == 0U) { 519*91f16700Schasinglulu continue; 520*91f16700Schasinglulu } 521*91f16700Schasinglulu 522*91f16700Schasinglulu cirq_id = (reg->reg_num << 5U) + cirq_bit; 523*91f16700Schasinglulu mt_irq_set_pending(CIRQ_TO_IRQ_NUM(cirq_id)); 524*91f16700Schasinglulu if (CIRQ_TO_IRQ_NUM(cirq_id) == MD_WDT_IRQ_BIT_ID) { 525*91f16700Schasinglulu INFO("Set MD_WDT_IRQ pending in %s\n", 526*91f16700Schasinglulu __func__); 527*91f16700Schasinglulu } 528*91f16700Schasinglulu } 529*91f16700Schasinglulu } 530*91f16700Schasinglulu } 531*91f16700Schasinglulu 532*91f16700Schasinglulu /* 533*91f16700Schasinglulu * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC 534*91f16700Schasinglulu */ 535*91f16700Schasinglulu void mt_cirq_flush(void) 536*91f16700Schasinglulu { 537*91f16700Schasinglulu cirq_fast_sw_flush(); 538*91f16700Schasinglulu mt_cirq_mask_all(); 539*91f16700Schasinglulu mt_cirq_ack_all(); 540*91f16700Schasinglulu } 541*91f16700Schasinglulu 542*91f16700Schasinglulu void mt_cirq_sw_reset(void) 543*91f16700Schasinglulu { 544*91f16700Schasinglulu uint32_t st; 545*91f16700Schasinglulu 546*91f16700Schasinglulu st = mmio_read_32(CIRQ_CON); 547*91f16700Schasinglulu st |= (CIRQ_SW_RESET << CIRQ_CON_SW_RST_BITS); 548*91f16700Schasinglulu mmio_write_32(CIRQ_CON, st); 549*91f16700Schasinglulu } 550