From: G.Pangao Date: Fri, 6 Nov 2020 01:20:25 +0000 (+0800) Subject: mediatek: mt8192: modify sys_cirq driver X-Git-Tag: baikal/aarch64/sdk5.9~1071^2~4 X-Git-Url: https://git.baikalelectronics.ru/?a=commitdiff_plain;h=49fd68abe46dbbb69027283527cc5c9d8a81b678;p=arm-tf.git mediatek: mt8192: modify sys_cirq driver 1.Modify this driver to make it more complete and more standard. 2.And makes this driver available for more IC services. 3.Solve some bugs in the software. Signed-off-by: G.Pangao Change-Id: I284956d47ebbbd550ec93767679181185e442348 --- diff --git a/plat/mediatek/mt8192/include/plat_mt_cirq.h b/plat/mediatek/mt8192/include/plat_mt_cirq.h index 581860109..bb8b4577f 100644 --- a/plat/mediatek/mt8192/include/plat_mt_cirq.h +++ b/plat/mediatek/mt8192/include/plat_mt_cirq.h @@ -7,24 +7,53 @@ #ifndef PLAT_MT_CIRQ_H #define PLAT_MT_CIRQ_H -#define SYS_CIRQ_BASE U(0x10204000) -#define CIRQ_IRQ_NUM U(439) -#define CIRQ_SPI_START U(96) +#include + +enum { + IRQ_MASK_HEADER = 0xF1F1F1F1, + IRQ_MASK_FOOTER = 0xF2F2F2F2 +}; + +struct mtk_irq_mask { + uint32_t header; /* for error checking */ + uint32_t mask0; + uint32_t mask1; + uint32_t mask2; + uint32_t mask3; + uint32_t mask4; + uint32_t mask5; + uint32_t mask6; + uint32_t mask7; + uint32_t mask8; + uint32_t mask9; + uint32_t mask10; + uint32_t mask11; + uint32_t mask12; + uint32_t footer; /* for error checking */ +}; + /* * Define hardware register */ -#define CIRQ_STA_BASE U(0x000) -#define CIRQ_ACK_BASE U(0x080) -#define CIRQ_MASK_BASE U(0x100) -#define CIRQ_MASK_SET_BASE U(0x180) -#define CIRQ_MASK_CLR_BASE U(0x200) -#define CIRQ_SENS_BASE U(0x280) -#define CIRQ_SENS_SET_BASE U(0x300) -#define CIRQ_SENS_CLR_BASE U(0x380) -#define CIRQ_POL_BASE U(0x400) -#define CIRQ_POL_SET_BASE U(0x480) -#define CIRQ_POL_CLR_BASE U(0x500) -#define CIRQ_CON U(0x600) + +#define SYS_CIRQ_BASE U(0x10204000) +#define CIRQ_REG_NUM U(14) +#define CIRQ_IRQ_NUM U(439) +#define CIRQ_SPI_START U(64) +#define MD_WDT_IRQ_BIT_ID U(110) + +#define CIRQ_STA_BASE (SYS_CIRQ_BASE + U(0x000)) +#define CIRQ_ACK_BASE (SYS_CIRQ_BASE + U(0x080)) +#define CIRQ_MASK_BASE (SYS_CIRQ_BASE + U(0x100)) +#define CIRQ_MASK_SET_BASE (SYS_CIRQ_BASE + U(0x180)) +#define CIRQ_MASK_CLR_BASE (SYS_CIRQ_BASE + U(0x200)) +#define CIRQ_SENS_BASE (SYS_CIRQ_BASE + U(0x280)) +#define CIRQ_SENS_SET_BASE (SYS_CIRQ_BASE + U(0x300)) +#define CIRQ_SENS_CLR_BASE (SYS_CIRQ_BASE + U(0x380)) +#define CIRQ_POL_BASE (SYS_CIRQ_BASE + U(0x400)) +#define CIRQ_POL_SET_BASE (SYS_CIRQ_BASE + U(0x480)) +#define CIRQ_POL_CLR_BASE (SYS_CIRQ_BASE + U(0x500)) +#define CIRQ_CON (SYS_CIRQ_BASE + U(0x600)) /* * Register placement @@ -32,8 +61,8 @@ #define CIRQ_CON_EN_BITS U(0) #define CIRQ_CON_EDGE_ONLY_BITS U(1) #define CIRQ_CON_FLUSH_BITS U(2) -#define CIRQ_CON_EVENT_BITS U(31) #define CIRQ_CON_SW_RST_BITS U(20) +#define CIRQ_CON_EVENT_BITS U(31) #define CIRQ_CON_BITS_MASK U(0x7) /* @@ -41,42 +70,59 @@ */ #define CIRQ_CON_EN U(0x1) #define CIRQ_CON_EDGE_ONLY U(0x1) -#define CIRQ_SW_RESET U(0x1) #define CIRQ_CON_FLUSH U(0x1) +#define CIRQ_SW_RESET U(0x1) /* * Define constant */ #define CIRQ_CTRL_REG_NUM ((CIRQ_IRQ_NUM + 31U) / 32U) -#define MT_CIRQ_POL_NEG U(0) -#define MT_CIRQ_POL_POS U(1) -#define MT_CIRQ_EDGE_SENSITIVE U(0) -#define MT_CIRQ_LEVEL_SENSITIVE U(1) -/* - * Define macro - */ -#define IRQ_TO_CIRQ_NUM(irq) ((irq) - (CIRQ_SPI_START)) -#define CIRQ_TO_IRQ_NUM(cirq) ((cirq) + (CIRQ_SPI_START)) +#define MT_CIRQ_POL_NEG U(0) +#define MT_CIRQ_POL_POS U(1) + +#define IRQ_TO_CIRQ_NUM(irq) ((irq) - (32U + CIRQ_SPI_START)) +#define CIRQ_TO_IRQ_NUM(cirq) ((cirq) + (32U + CIRQ_SPI_START)) + +/* GIC sensitive */ +#define SENS_EDGE U(0x2) +#define SENS_LEVEL U(0x1) -/* - * Define cirq events - */ -struct cirq_events { - uint32_t spi_start; - uint32_t num_of_events; - uint32_t *wakeup_events; -}; /* * Define function prototypes. */ -void mt_cirq_enable(void); -void mt_cirq_disable(void); +int mt_cirq_test(void); +void mt_cirq_dump_reg(void); +int mt_irq_mask_restore(struct mtk_irq_mask *mask); +int mt_irq_mask_all(struct mtk_irq_mask *mask); void mt_cirq_clone_gic(void); +void mt_cirq_enable(void); void mt_cirq_flush(void); -void mt_cirq_sw_reset(void); +void mt_cirq_disable(void); +void mt_irq_unmask_for_sleep_ex(uint32_t irq); void set_wakeup_sources(uint32_t *list, uint32_t num_of_events); -void mt_cirq_dump_reg(void); +void mt_cirq_sw_reset(void); + +struct cirq_reg { + uint32_t reg_num; + uint32_t used; + uint32_t mask; + uint32_t pol; + uint32_t sen; + uint32_t pending; + uint32_t the_link; +}; + +struct cirq_events { + uint32_t num_reg; + uint32_t spi_start; + uint32_t num_of_events; + uint32_t *wakeup_events; + struct cirq_reg table[CIRQ_REG_NUM]; + uint32_t dist_base; + uint32_t cirq_base; + uint32_t used_reg_head; +}; -#endif /* PLAT_MT_CIRQ_H */ +#endif /* PLAT_MT_CIRQ_H */ diff --git a/plat/mediatek/mt8192/plat_mt_cirq.c b/plat/mediatek/mt8192/plat_mt_cirq.c index 7fc060799..9002b7ee1 100644 --- a/plat/mediatek/mt8192/plat_mt_cirq.c +++ b/plat/mediatek/mt8192/plat_mt_cirq.c @@ -7,137 +7,255 @@ #include #include #include -#include #include #include -#include #include #include static struct cirq_events cirq_all_events = { - .spi_start = CIRQ_SPI_START + .spi_start = CIRQ_SPI_START, }; - -static inline void mt_cirq_write32(uint32_t val, uint32_t addr) -{ - mmio_write_32(addr + SYS_CIRQ_BASE, val); -} - -static inline uint32_t mt_cirq_read32(uint32_t addr) -{ - return mmio_read_32(addr + SYS_CIRQ_BASE); -} - +static uint32_t already_cloned; /* - * cirq_clone_flush_check_store: - * set 1 if we need to enable clone/flush value's check + * mt_irq_mask_restore: restore all interrupts + * @mask: pointer to struct mtk_irq_mask for storing the original mask value. + * Return 0 for success; return negative values for failure. + * (This is ONLY used for the idle current measurement by the factory mode.) */ -static int32_t cirq_clone_flush_check_val; +int mt_irq_mask_restore(struct mtk_irq_mask *mask) +{ + if (mask == NULL) { + return -1; + } + if (mask->header != IRQ_MASK_HEADER) { + return -1; + } + if (mask->footer != IRQ_MASK_FOOTER) { + return -1; + } -/* - * cirq_pattern_clone_flush_check_show: set 1 if we need to do pattern test. - */ -static int32_t cirq_pattern_clone_flush_check_val; + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x4), + mask->mask1); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x8), + mask->mask2); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0xc), + mask->mask3); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x10), + mask->mask4); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x14), + mask->mask5); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x18), + mask->mask6); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x1c), + mask->mask7); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x20), + mask->mask8); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x24), + mask->mask9); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x28), + mask->mask10); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x2c), + mask->mask11); + mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x30), + mask->mask12); + /* make sure dist changes happen */ + dsb(); -/* - * cirq_pattern_clone_flush_check_show: set 1 if we need to do pattern test. - */ -static int32_t cirq_pattern_list; + return 0; +} /* - * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ + * mt_irq_mask_all: disable all interrupts + * @mask: pointer to struct mtk_irq_mask for storing the original mask value. + * Return 0 for success; return negative values for failure. + * (This is ONLY used for the idle current measurement by the factory mode.) */ -void mt_cirq_ack_all(void) +int mt_irq_mask_all(struct mtk_irq_mask *mask) { - unsigned int i; - - for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { - mt_cirq_write32(0xFFFFFFFF, CIRQ_ACK_BASE + (i * 4U)); + if (mask != NULL) { + /* for SPI */ + mask->mask1 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x4)); + mask->mask2 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x8)); + mask->mask3 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0xc)); + mask->mask4 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x10)); + mask->mask5 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x14)); + mask->mask6 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x18)); + mask->mask7 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x1c)); + mask->mask8 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x20)); + mask->mask9 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x24)); + mask->mask10 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x28)); + mask->mask11 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x2c)); + mask->mask12 = mmio_read_32((BASE_GICD_BASE + + GICD_ISENABLER + 0x30)); + + /* for SPI */ + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x4), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x8), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0xC), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x10), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x14), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x18), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x1C), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x20), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x24), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x28), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x2c), + 0xFFFFFFFF); + mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x30), + 0xFFFFFFFF); + /* make sure distributor changes happen */ + dsb(); + + mask->header = IRQ_MASK_HEADER; + mask->footer = IRQ_MASK_FOOTER; + + return 0; + } else { + return -1; } - /* make sure all cirq setting take effect before doing other things */ - dmbsy(); } -/* - * mt_cirq_enable: Enable SYS_CIRQ - */ -void mt_cirq_enable(void) +static uint32_t mt_irq_get_pol(uint32_t irq) { - uint32_t st; +#ifdef CIRQ_WITH_POLARITY + uint32_t reg; + uint32_t base = INT_POL_CTL0; - mt_cirq_ack_all(); + if (irq < 32U) { + return 0; + } - st = mt_cirq_read32(CIRQ_CON); - st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS) | - (CIRQ_CON_EDGE_ONLY << CIRQ_CON_EDGE_ONLY_BITS); + reg = ((irq - 32U) / 32U); - mt_cirq_write32((st & CIRQ_CON_BITS_MASK), CIRQ_CON); + return mmio_read_32(base + reg * 4U); +#else + return 0; +#endif } -/* - * mt_cirq_disable: Disable SYS_CIRQ - */ -void mt_cirq_disable(void) +unsigned int mt_irq_get_sens(unsigned int irq) { - uint32_t st; + unsigned int config; - st = mt_cirq_read32(CIRQ_CON); - st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS); + /* + * 2'b10 edge + * 2'b01 level + */ + config = mmio_read_32(MT_GIC_BASE + GICD_ICFGR + (irq / 16U) * 4U); + config = (config >> (irq % 16U) * 2U) & 0x3; - mt_cirq_write32((st & CIRQ_CON_BITS_MASK), CIRQ_CON); + return config; } -/* - * mt_cirq_get_mask: Get the specified SYS_CIRQ mask - * @cirq_num: the SYS_CIRQ number to get - * @return: - * 1: this cirq is masked - * 0: this cirq is umasked - * 2: cirq num is out of range - */ -__attribute__((weak)) unsigned int mt_cirq_get_mask(uint32_t cirq_num) +static void collect_all_wakeup_events(void) { - uint32_t st; - unsigned int val; - - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return 2; + unsigned int i; + uint32_t gic_irq; + uint32_t cirq; + uint32_t cirq_reg; + uint32_t cirq_offset; + uint32_t mask; + uint32_t pol_mask; + uint32_t irq_offset; + uint32_t irq_mask; + + if ((cirq_all_events.wakeup_events == NULL) || + cirq_all_events.num_of_events == 0U) { + return; } - st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_MASK_BASE); - val = (st >> (cirq_num % 32U)) & 1U; - return val; -} - -/* - * mt_cirq_mask_all: Mask all interrupts on SYS_CIRQ. - */ -void mt_cirq_mask_all(void) -{ - unsigned int i; + for (i = 0U; i < cirq_all_events.num_of_events; i++) { + if (cirq_all_events.wakeup_events[i] > 0U) { + gic_irq = cirq_all_events.wakeup_events[i]; + cirq = gic_irq - cirq_all_events.spi_start - 32U; + cirq_reg = cirq / 32U; + cirq_offset = cirq % 32U; + mask = 0x1 << cirq_offset; + irq_offset = gic_irq % 32U; + irq_mask = 0x1 << irq_offset; + /* + * CIRQ default masks all + */ + cirq_all_events.table[cirq_reg].mask |= mask; + /* + * CIRQ default pol is low + */ + pol_mask = mt_irq_get_pol( + cirq_all_events.wakeup_events[i]) + & irq_mask; + /* + * 0 means rising + */ + if (pol_mask == 0U) { + cirq_all_events.table[cirq_reg].pol |= mask; + } + /* + * CIRQ could monitor edge/level trigger + * cirq register (0: edge, 1: level) + */ + if (mt_irq_get_sens(cirq_all_events.wakeup_events[i]) + == SENS_EDGE) { + cirq_all_events.table[cirq_reg].sen |= mask; + } - for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { - mt_cirq_write32(0xFFFFFFFF, CIRQ_MASK_SET_BASE + (i * 4U)); + cirq_all_events.table[cirq_reg].used = 1U; + cirq_all_events.table[cirq_reg].reg_num = cirq_reg; + } } - /* make sure all cirq setting take effect before doing other things */ - dmbsy(); } /* - * mt_cirq_unmask_all: Unmask all interrupts on SYS_CIRQ. + * mt_cirq_set_pol: Set the polarity for the specified SYS_CIRQ number. + * @cirq_num: the SYS_CIRQ number to set + * @pol: polarity to set + * @return: + * 0: set pol success + * -1: cirq num is out of range */ -void mt_cirq_unmask_all(void) +#ifdef CIRQ_WITH_POLARITY +static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol) { - unsigned int i; + uint32_t base; + uint32_t bit = 1U << (cirq_num % 32U); - for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { - mt_cirq_write32(0xFFFFFFFF, CIRQ_MASK_CLR_BASE + (i * 4U)); + if (cirq_num >= CIRQ_IRQ_NUM) { + return -1; + } + + if (pol == MT_CIRQ_POL_NEG) { + base = (cirq_num / 32U) * 4U + CIRQ_POL_CLR_BASE; + } else if (pol == MT_CIRQ_POL_POS) { + base = (cirq_num / 32U) * 4U + CIRQ_POL_SET_BASE; + } else { + return -1; } - /* make sure all cirq setting take effect before doing other things */ - dmbsy(); + + mmio_write_32(base, bit); + return 0; } +#endif /* * mt_cirq_mask: Mask the specified SYS_CIRQ. @@ -151,11 +269,11 @@ static int mt_cirq_mask(uint32_t cirq_num) uint32_t bit = 1U << (cirq_num % 32U); if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); return -1; } - mt_cirq_write32(bit, (cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE); + mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE, bit); + return 0; } @@ -171,324 +289,264 @@ static int mt_cirq_unmask(uint32_t cirq_num) uint32_t bit = 1U << (cirq_num % 32U); if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); return -1; } - mt_cirq_write32(bit, (cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE); + mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE, bit); + return 0; } -/* - * mt_cirq_set_sens: Set the sensitivity for the specified SYS_CIRQ number. - * @cirq_num: the SYS_CIRQ number to set - * @sens: sensitivity to set - * @return: - * 0: set sens success - * -1: cirq num is out of range - */ -static int mt_cirq_set_sens(uint32_t cirq_num, uint32_t sens) +uint32_t mt_irq_get_en(uint32_t irq) { - uint32_t base; - uint32_t bit = 1U << (cirq_num % 32U); + uint32_t addr, st, val; - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return -1; - } + addr = BASE_GICD_BASE + GICD_ISENABLER + (irq / 32U) * 4U; + st = mmio_read_32(addr); - if (sens == MT_CIRQ_EDGE_SENSITIVE) { - base = (cirq_num / 32U) * 4U + CIRQ_SENS_CLR_BASE; - } else if (sens == MT_CIRQ_LEVEL_SENSITIVE) { - base = (cirq_num / 32U) * 4U + CIRQ_SENS_SET_BASE; - } else { - ERROR("[CIRQ] set_sens invalid sen value %u\n", sens); - return -1; - } + val = (st >> (irq % 32U)) & 1U; - mt_cirq_write32(bit, base); - return 0; + return val; } -/* - * mt_cirq_get_sens: Get the specified SYS_CIRQ sensitivity - * @cirq_num: the SYS_CIRQ number to get - * @return: - * 1: this cirq is MT_LEVEL_SENSITIVE - * 0: this cirq is MT_EDGE_SENSITIVE - * 2: cirq num is out of range - */ -__attribute__((weak)) unsigned int mt_cirq_get_sens(uint32_t cirq_num) +static void __cirq_fast_clone(void) { - uint32_t st; - unsigned int val; + struct cirq_reg *reg; + unsigned int i; - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return 2; - } + for (i = 0U; i < CIRQ_REG_NUM ; ++i) { + uint32_t cirq_bit; - st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_SENS_BASE); - val = (st >> (cirq_num % 32U)) & 1U; - return val; -} + reg = &cirq_all_events.table[i]; -/* - * mt_cirq_set_pol: Set the polarity for the specified SYS_CIRQ number. - * @cirq_num: the SYS_CIRQ number to set - * @pol: polarity to set - * @return: - * 0: set pol success - * -1: cirq num is out of range - */ -static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol) -{ - uint32_t base; - uint32_t bit = 1U << (cirq_num % 32U); + if (reg->used == 0U) { + continue; + } - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return -1; - } + mmio_write_32(CIRQ_SENS_CLR_BASE + (reg->reg_num * 4U), + reg->sen); - if (pol == MT_CIRQ_POL_NEG) { - base = (cirq_num / 32U) * 4U + CIRQ_POL_CLR_BASE; - } else if (pol == MT_CIRQ_POL_POS) { - base = (cirq_num / 32U) * 4U + CIRQ_POL_SET_BASE; - } else { - ERROR("[CIRQ] set_pol invalid polarity value %u\n", pol); - return -1; - } + for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) { + uint32_t val, cirq_id; + uint32_t gic_id; +#ifdef CIRQ_WITH_POLARITY + uint32_t gic_bit, pol; +#endif + uint32_t en; - mt_cirq_write32(bit, base); - return 0; -} + val = ((1U << cirq_bit) & reg->mask); -/* - * mt_cirq_get_pol: Get the specified SYS_CIRQ polarity - * @cirq_num: the SYS_CIRQ number to get - * @return: - * 1: this cirq is MT_CIRQ_POL_POS - * 0: this cirq is MT_CIRQ_POL_NEG - * 2: cirq num is out of range - */ -__attribute__((weak)) unsigned int mt_cirq_get_pol(uint32_t cirq_num) -{ - uint32_t st; - unsigned int val; + if (val == 0U) { + continue; + } - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return 2; + cirq_id = (reg->reg_num << 5U) + cirq_bit; + gic_id = CIRQ_TO_IRQ_NUM(cirq_id); +#ifdef CIRQ_WITH_POLARITY + gic_bit = (0x1U << ((gic_id - 32U) % 32U)); + pol = mt_irq_get_pol(gic_id) & gic_bit; + if (pol != 0U) { + mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_NEG); + } else { + mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_POS); + } +#endif + en = mt_irq_get_en(gic_id); + if (en == 1U) { + mt_cirq_unmask(cirq_id); + } else { + mt_cirq_mask(cirq_id); + } + } } +} - st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_POL_BASE); - val = (st >> (cirq_num % 32U)) & 1U; - return val; +static void cirq_fast_clone(void) +{ + if (already_cloned == 0U) { + collect_all_wakeup_events(); + already_cloned = 1U; + } + __cirq_fast_clone(); } +void set_wakeup_sources(uint32_t *list, uint32_t num_of_events) +{ + cirq_all_events.num_of_events = num_of_events; + cirq_all_events.wakeup_events = list; +} /* - * mt_cirq_get_pending: Get the specified SYS_CIRQ pending - * @cirq_num: the SYS_CIRQ number to get - * @return: - * 1: this cirq is pending - * 0: this cirq is not pending - * 2: cirq num is out of range + * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ */ -static unsigned int mt_cirq_get_pending(uint32_t cirq_num) +void mt_cirq_clone_gic(void) { - uint32_t st; - unsigned int val; + cirq_fast_clone(); +} - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return 2; +uint32_t mt_irq_get_pending_vec(uint32_t start_irq) +{ + uint32_t base = 0U; + uint32_t pending_vec = 0U; + uint32_t reg = start_irq / 32U; + uint32_t LSB_num, MSB_num; + uint32_t LSB_vec, MSB_vec; + + base = BASE_GICD_BASE; + + /* if start_irq is not aligned 32, do some assembling */ + MSB_num = start_irq % 32U; + if (MSB_num != 0U) { + LSB_num = 32U - MSB_num; + LSB_vec = mmio_read_32(base + GICD_ISPENDR + + reg * 4U) >> MSB_num; + MSB_vec = mmio_read_32(base + GICD_ISPENDR + + (reg + 1U) * 4U) << LSB_num; + pending_vec = MSB_vec | LSB_vec; + } else { + pending_vec = mmio_read_32(base + GICD_ISPENDR + reg * 4); } - st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_STA_BASE); - val = (st >> (cirq_num % 32U)) & 1U; - return val; + return pending_vec; +} + +static int mt_cirq_get_mask_vec(unsigned int i) +{ + return mmio_read_32((i * 4U) + CIRQ_MASK_BASE); } /* - * mt_cirq_clone_pol: Copy the polarity setting from GIC to SYS_CIRQ + * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ */ -void mt_cirq_clone_pol(void) +void mt_cirq_ack_all(void) { - uint32_t cirq_num; + uint32_t ack_vec, pend_vec, mask_vec; + unsigned int i; - for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) { - mt_cirq_set_pol(cirq_num, MT_CIRQ_POL_POS); + for (i = 0; i < CIRQ_CTRL_REG_NUM; i++) { + /* + * if a irq is pending & not masked, don't ack it + * , since cirq start irq might not be 32 aligned with gic, + * need an exotic API to get proper vector of pending irq + */ + pend_vec = mt_irq_get_pending_vec(CIRQ_SPI_START + + (i + 1U) * 32U); + mask_vec = mt_cirq_get_mask_vec(i); + /* those should be acked are: "not (pending & not masked)", + */ + ack_vec = (~pend_vec) | mask_vec; + mmio_write_32(CIRQ_ACK_BASE + (i * 4U), ack_vec); } -} + /* + * make sure all cirq setting take effect + * before doing other things + */ + dsb(); +} /* - * mt_cirq_clone_sens: Copy the sensitivity setting from GIC to SYS_CIRQ + * mt_cirq_enable: Enable SYS_CIRQ */ -void mt_cirq_clone_sens(void) +void mt_cirq_enable(void) { - uint32_t cirq_num, irq_num; - uint32_t st, val; - - for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) { - irq_num = CIRQ_TO_IRQ_NUM(cirq_num); + uint32_t st; - if ((cirq_num == 0U) || (irq_num % 16U == 0U)) { - st = mmio_read_32(BASE_GICD_BASE + GICD_ICFGR + - (irq_num / 16U * 4U)); - } + /* level only */ + mt_cirq_ack_all(); - val = (st >> ((irq_num % 16U) * 2U)) & 0x2U; + st = mmio_read_32(CIRQ_CON); + /* + * CIRQ could monitor edge/level trigger + */ + st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS); - if (val) { - mt_cirq_set_sens(cirq_num, MT_CIRQ_EDGE_SENSITIVE); - } else { - mt_cirq_set_sens(cirq_num, MT_CIRQ_LEVEL_SENSITIVE); - } - } + mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK)); } /* - * mt_cirq_clone_mask: Copy the mask setting from GIC to SYS_CIRQ + * mt_cirq_disable: Disable SYS_CIRQ */ -void mt_cirq_clone_mask(void) +void mt_cirq_disable(void) { - uint32_t cirq_num, irq_num; - uint32_t st, val; + uint32_t st; - for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) { - irq_num = CIRQ_TO_IRQ_NUM(cirq_num); + st = mmio_read_32(CIRQ_CON); + st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS); + mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK)); +} - if ((cirq_num == 0U) || (irq_num % 32U == 0U)) { - st = mmio_read_32(BASE_GICD_BASE + - GICD_ISENABLER + (irq_num / 32U * 4U)); - } +void mt_irq_unmask_for_sleep_ex(uint32_t irq) +{ + uint32_t mask; - val = (st >> (irq_num % 32)) & 1U; + mask = 1U << (irq % 32U); - if (val) { - mt_cirq_unmask(cirq_num); - } else { - mt_cirq_mask(cirq_num); - } - } + mmio_write_32(BASE_GICD_BASE + GICD_ISENABLER + + ((irq / 32U) * 4U), mask); } -/* - * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ - */ -void mt_cirq_clone_gic(void) +void mt_cirq_mask_all(void) { - mt_cirq_clone_sens(); - mt_cirq_clone_mask(); + unsigned int i; + + for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { + mmio_write_32(CIRQ_MASK_SET_BASE + (i * 4U), 0xFFFFFFFF); + } + dsb(); } -/* - * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC - */ -void mt_cirq_flush(void) +static void cirq_fast_sw_flush(void) { + struct cirq_reg *reg; unsigned int i; - unsigned char cirq_p_val = 0U; - unsigned char irq_p_val = 0U; - uint32_t irq_p = 0U; - unsigned char pass = 1U; - uint32_t first_cirq_found = 0U; - uint32_t first_flushed_cirq; - uint32_t first_irq_flushedto; - uint32_t last_fluashed_cirq; - uint32_t last_irq_flushedto; - - if (cirq_pattern_clone_flush_check_val == 1U) { - if (cirq_pattern_list < CIRQ_IRQ_NUM) { - mt_cirq_unmask(cirq_pattern_list); - mt_cirq_set_sens(cirq_pattern_list, - MT_CIRQ_EDGE_SENSITIVE); - mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_NEG); - mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_POS); - mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_NEG); - } else { - ERROR("[CIRQ] no pattern to test,"); - ERROR("input pattern first\n"); - } - ERROR("[CIRQ] cirq_pattern %u, cirq_p %u,", - cirq_pattern_list, - mt_cirq_get_pending(cirq_pattern_list)); - ERROR("cirq_s %u, cirq_con 0x%x\n", - mt_cirq_get_sens(cirq_pattern_list), - mt_cirq_read32(CIRQ_CON)); - } - mt_cirq_unmask_all(); + for (i = 0U; i < CIRQ_REG_NUM ; ++i) { + uint32_t cirq_bit; - for (i = 0U; i < CIRQ_IRQ_NUM; i++) { - cirq_p_val = mt_cirq_get_pending(i); - if (cirq_p_val) { - mt_irq_set_pending(CIRQ_TO_IRQ_NUM(i)); + reg = &cirq_all_events.table[i]; + + if (reg->used == 0U) { + continue; } - if (cirq_clone_flush_check_val == 1U) { - if (cirq_p_val == 0U) { + reg->pending = mmio_read_32(CIRQ_STA_BASE + + (reg->reg_num << 2U)); + reg->pending &= reg->mask; + + for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) { + uint32_t val, cirq_id; + + val = (1U << cirq_bit) & reg->pending; + if (val == 0U) { continue; - } - irq_p = CIRQ_TO_IRQ_NUM(i); - irq_p_val = mt_irq_get_pending(irq_p); - if (cirq_p_val != irq_p_val) { - ERROR("[CIRQ] CIRQ Flush Failed "); - ERROR("%u(cirq %d)!= %u(gic %d)\n", - cirq_p_val, i, irq_p_val, - CIRQ_TO_IRQ_NUM(i)); - pass = 0; - } else { - ERROR("[CIRQ] CIRQ Flush Pass "); - ERROR("%u(cirq %d) = %u(gic %d)\n", - cirq_p_val, i, irq_p_val, - CIRQ_TO_IRQ_NUM(i)); } - if (!first_cirq_found) { - first_flushed_cirq = i; - first_irq_flushedto = irq_p; - first_cirq_found = 1U; + + cirq_id = (reg->reg_num << 5U) + cirq_bit; + mt_irq_set_pending(CIRQ_TO_IRQ_NUM(cirq_id)); + if (CIRQ_TO_IRQ_NUM(cirq_id) == MD_WDT_IRQ_BIT_ID) { + INFO("Set MD_WDT_IRQ pending in %s\n", + __func__); } - last_fluashed_cirq = i; - last_irq_flushedto = irq_p; } } +} - if (cirq_clone_flush_check_val == 1U) { - if (first_cirq_found) { - ERROR("[CIRQ] The first flush : CIRQ%u to IRQ%u\n", - first_flushed_cirq, first_irq_flushedto); - ERROR("[CIRQ] The last flush : CIRQ%u to IRQ%u\n", - last_fluashed_cirq, last_irq_flushedto); - } else { - ERROR("[CIRQ] There are no pending "); - ERROR("interrupt in CIRQ\n"); - ERROR("[CIRQ] so no flush operation happened\n"); - } - ERROR("[CIRQ] The Flush Max Range : CIRQ"); - ERROR("%d to IRQ%d ~ CIRQ%d to IRQ%d\n", 0U, - CIRQ_TO_IRQ_NUM(0U), CIRQ_IRQ_NUM - 1U, - CIRQ_TO_IRQ_NUM(CIRQ_IRQ_NUM - 1U)); - ERROR("[CIRQ] Flush Check %s, Confirm:SPI_START_OFFSET:%d\n", - pass == 1 ? "Pass" : "Failed", CIRQ_SPI_START); - } +/* + * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC + */ +void mt_cirq_flush(void) +{ + cirq_fast_sw_flush(); mt_cirq_mask_all(); mt_cirq_ack_all(); } void mt_cirq_sw_reset(void) { +#ifdef CIRQ_NEED_SW_RESET uint32_t st; - st = mt_cirq_read32(CIRQ_CON); + st = mmio_read_32(CIRQ_CON); st |= (CIRQ_SW_RESET << CIRQ_CON_SW_RST_BITS); - - mt_cirq_write32(st, CIRQ_CON); -} - -void set_wakeup_sources(uint32_t *list, uint32_t num_of_events) -{ - cirq_all_events.num_of_events = num_of_events; - cirq_all_events.wakeup_events = list; + mmio_write_32(CIRQ_CON, st); +#endif }