diff --git a/plat/mediatek/mt8192/include/mt_gic_v3.h b/plat/mediatek/mt8192/include/mt_gic_v3.h index 34ba8a7..c4ab44f 100644 --- a/plat/mediatek/mt8192/include/mt_gic_v3.h +++ b/plat/mediatek/mt8192/include/mt_gic_v3.h @@ -21,4 +21,7 @@ void mt_gic_rdistif_restore_all(void); void gic_sgi_save_all(void); void gic_sgi_restore_all(void); +uint32_t mt_irq_get_pending(uint32_t irq); +void mt_irq_set_pending(uint32_t irq); + #endif /* MT_GIC_V3_H */ diff --git a/plat/mediatek/mt8192/include/plat_mt_cirq.h b/plat/mediatek/mt8192/include/plat_mt_cirq.h new file mode 100644 index 0000000..5818601 --- /dev/null +++ b/plat/mediatek/mt8192/include/plat_mt_cirq.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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) +/* + * 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) + +/* + * Register placement + */ +#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_BITS_MASK U(0x7) + +/* + * Register setting + */ +#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 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 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); +void mt_cirq_clone_gic(void); +void mt_cirq_flush(void); +void mt_cirq_sw_reset(void); +void set_wakeup_sources(uint32_t *list, uint32_t num_of_events); +void mt_cirq_dump_reg(void); + +#endif /* PLAT_MT_CIRQ_H */ diff --git a/plat/mediatek/mt8192/plat_mt_cirq.c b/plat/mediatek/mt8192/plat_mt_cirq.c new file mode 100644 index 0000000..7fc0607 --- /dev/null +++ b/plat/mediatek/mt8192/plat_mt_cirq.c @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct cirq_events cirq_all_events = { + .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); +} + +/* + * cirq_clone_flush_check_store: + * set 1 if we need to enable clone/flush value's check + */ +static int32_t cirq_clone_flush_check_val; + +/* + * cirq_pattern_clone_flush_check_show: set 1 if we need to do pattern test. + */ +static int32_t cirq_pattern_clone_flush_check_val; + +/* + * cirq_pattern_clone_flush_check_show: set 1 if we need to do pattern test. + */ +static int32_t cirq_pattern_list; + +/* + * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ + */ +void mt_cirq_ack_all(void) +{ + unsigned int i; + + for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { + mt_cirq_write32(0xFFFFFFFF, CIRQ_ACK_BASE + (i * 4U)); + } + /* make sure all cirq setting take effect before doing other things */ + dmbsy(); +} + +/* + * mt_cirq_enable: Enable SYS_CIRQ + */ +void mt_cirq_enable(void) +{ + uint32_t st; + + mt_cirq_ack_all(); + + st = mt_cirq_read32(CIRQ_CON); + st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS) | + (CIRQ_CON_EDGE_ONLY << CIRQ_CON_EDGE_ONLY_BITS); + + mt_cirq_write32((st & CIRQ_CON_BITS_MASK), CIRQ_CON); +} + +/* + * mt_cirq_disable: Disable SYS_CIRQ + */ +void mt_cirq_disable(void) +{ + uint32_t st; + + st = mt_cirq_read32(CIRQ_CON); + st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS); + + mt_cirq_write32((st & CIRQ_CON_BITS_MASK), CIRQ_CON); +} + +/* + * 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) +{ + uint32_t st; + unsigned int val; + + if (cirq_num >= CIRQ_IRQ_NUM) { + ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); + return 2; + } + + 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_CTRL_REG_NUM; i++) { + mt_cirq_write32(0xFFFFFFFF, CIRQ_MASK_SET_BASE + (i * 4U)); + } + /* make sure all cirq setting take effect before doing other things */ + dmbsy(); +} + +/* + * mt_cirq_unmask_all: Unmask all interrupts on SYS_CIRQ. + */ +void mt_cirq_unmask_all(void) +{ + unsigned int i; + + for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { + mt_cirq_write32(0xFFFFFFFF, CIRQ_MASK_CLR_BASE + (i * 4U)); + } + /* make sure all cirq setting take effect before doing other things */ + dmbsy(); +} + +/* + * mt_cirq_mask: Mask the specified SYS_CIRQ. + * @cirq_num: the SYS_CIRQ number to mask + * @return: + * 0: mask success + * -1: cirq num is out of range + */ +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); + return 0; +} + +/* + * mt_cirq_unmask: Unmask the specified SYS_CIRQ. + * @cirq_num: the SYS_CIRQ number to unmask + * @return: + * 0: umask success + * -1: cirq num is out of range + */ +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); + 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 base; + 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; + } + + 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; + } + + mt_cirq_write32(bit, base); + return 0; +} + +/* + * 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) +{ + uint32_t st; + unsigned int val; + + if (cirq_num >= CIRQ_IRQ_NUM) { + ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); + return 2; + } + + st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_SENS_BASE); + val = (st >> (cirq_num % 32U)) & 1U; + return val; +} + +/* + * 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 (cirq_num >= CIRQ_IRQ_NUM) { + ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_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 { + ERROR("[CIRQ] set_pol invalid polarity value %u\n", pol); + return -1; + } + + mt_cirq_write32(bit, base); + return 0; +} + +/* + * 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 (cirq_num >= CIRQ_IRQ_NUM) { + ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); + return 2; + } + + st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_POL_BASE); + val = (st >> (cirq_num % 32U)) & 1U; + return val; +} + +/* + * 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 + */ +static unsigned int mt_cirq_get_pending(uint32_t cirq_num) +{ + uint32_t st; + unsigned int val; + + if (cirq_num >= CIRQ_IRQ_NUM) { + ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); + return 2; + } + + st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_STA_BASE); + val = (st >> (cirq_num % 32U)) & 1U; + return val; +} + +/* + * mt_cirq_clone_pol: Copy the polarity setting from GIC to SYS_CIRQ + */ +void mt_cirq_clone_pol(void) +{ + uint32_t cirq_num; + + for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) { + mt_cirq_set_pol(cirq_num, MT_CIRQ_POL_POS); + } +} + +/* + * mt_cirq_clone_sens: Copy the sensitivity setting from GIC to SYS_CIRQ + */ +void mt_cirq_clone_sens(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); + + if ((cirq_num == 0U) || (irq_num % 16U == 0U)) { + st = mmio_read_32(BASE_GICD_BASE + GICD_ICFGR + + (irq_num / 16U * 4U)); + } + + val = (st >> ((irq_num % 16U) * 2U)) & 0x2U; + + if (val) { + mt_cirq_set_sens(cirq_num, MT_CIRQ_EDGE_SENSITIVE); + } else { + mt_cirq_set_sens(cirq_num, MT_CIRQ_LEVEL_SENSITIVE); + } + } +} + +/* + * mt_cirq_clone_mask: Copy the mask setting from GIC to SYS_CIRQ + */ +void mt_cirq_clone_mask(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); + + if ((cirq_num == 0U) || (irq_num % 32U == 0U)) { + st = mmio_read_32(BASE_GICD_BASE + + GICD_ISENABLER + (irq_num / 32U * 4U)); + } + + val = (st >> (irq_num % 32)) & 1U; + + if (val) { + mt_cirq_unmask(cirq_num); + } else { + mt_cirq_mask(cirq_num); + } + } +} + +/* + * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ + */ +void mt_cirq_clone_gic(void) +{ + mt_cirq_clone_sens(); + mt_cirq_clone_mask(); +} + +/* + * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC + */ +void mt_cirq_flush(void) +{ + 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_IRQ_NUM; i++) { + cirq_p_val = mt_cirq_get_pending(i); + if (cirq_p_val) { + mt_irq_set_pending(CIRQ_TO_IRQ_NUM(i)); + } + + if (cirq_clone_flush_check_val == 1U) { + if (cirq_p_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; + } + 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_mask_all(); + mt_cirq_ack_all(); +} + +void mt_cirq_sw_reset(void) +{ + uint32_t st; + + st = mt_cirq_read32(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; +} diff --git a/plat/mediatek/mt8192/plat_mt_gic.c b/plat/mediatek/mt8192/plat_mt_gic.c index 593f5d0..ae8d697 100644 --- a/plat/mediatek/mt8192/plat_mt_gic.c +++ b/plat/mediatek/mt8192/plat_mt_gic.c @@ -175,3 +175,22 @@ gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } + +uint32_t mt_irq_get_pending(uint32_t irq) +{ + uint32_t val; + + val = mmio_read_32(BASE_GICD_BASE + GICD_ISPENDR + + irq / 32 * 4); + val = (val >> (irq % 32)) & 1U; + return val; +} + + +void mt_irq_set_pending(uint32_t irq) +{ + uint32_t bit = 1U << (irq % 32); + + mmio_write_32(BASE_GICD_BASE + GICD_ISPENDR + + irq / 32 * 4, bit); +} diff --git a/plat/mediatek/mt8192/platform.mk b/plat/mediatek/mt8192/platform.mk index 0d732d5..071700e 100644 --- a/plat/mediatek/mt8192/platform.mk +++ b/plat/mediatek/mt8192/platform.mk @@ -36,6 +36,7 @@ ${MTK_PLAT_SOC}/plat_pm.c \ ${MTK_PLAT_SOC}/plat_topology.c \ ${MTK_PLAT_SOC}/plat_mt_gic.c \ + ${MTK_PLAT_SOC}/plat_mt_cirq.c \ ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c