| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608 |
- /* Copyright Statement:
- *
- * This software/firmware and related documentation ("MediaTek Software") are
- * protected under relevant copyright laws. The information contained herein
- * is confidential and proprietary to MediaTek Inc. and/or its licensors.
- * Without the prior written permission of MediaTek inc. and/or its licensors,
- * any reproduction, modification, use or disclosure of MediaTek Software,
- * and information contained herein, in whole or in part, shall be strictly prohibited.
- */
- /* MediaTek Inc. (C) 2015. All rights reserved.
- *
- * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
- * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
- * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
- * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
- * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
- * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
- * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
- * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
- * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
- * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
- * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
- * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
- * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
- * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
- * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
- * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
- */
- #include <reg.h>
- #include <platform/mt_typedefs.h>
- #include <platform/mt_reg_base.h>
- #include <mt_gic.h>
- #include <mt_gic_v3.h>
- #include <debug.h>
- #define GICD_CTLR_RWP (1U << 31)
- #define GICD_CTLR_ARE (1 << 4)
- #define GICD_CTLR_ENGRP1S (1 << 2)
- #define GICD_CTLR_ENGRP1NS (1 << 1)
- #define GICR_WAKER_ProcessorSleep (1 << 1)
- #define GICR_WAKER_ChildrenAsleep (1 << 2)
- extern void dsb(void);
- extern void isb(void);
- extern uint32_t mt_interrupt_needed_for_secure(void);
- extern uint64_t mt_irq_get_affinity(void);
- static void mt_gic_icc_primask_write(uint32_t reg)
- {
- __asm__ volatile("MCR p15, 0, %0, c4, c6, 0" :: "r" (reg));
- }
- static uint32_t mt_gic_icc_primask_read(void)
- {
- uint32_t reg;
- __asm__ volatile("MRC p15, 0, %0, c4, c6, 0" : "=r" (reg));
- return reg;
- }
- static void mt_gic_icc_igrpen1_write(uint32_t reg)
- {
- __asm__ volatile("MCR p15, 0, %0, c12, c12, 7" :: "r" (reg));
- }
- static uint32_t mt_gic_icc_igrpen1_read(void)
- {
- uint32_t reg;
- __asm__ volatile("MRC p15, 0, %0, c12, c12, 7" : "=r" (reg));
- return reg;
- }
- static uint32_t mt_gic_icc_iar1_read(void)
- {
- uint32_t reg;
- __asm__ volatile("MRC p15, 0, %0, c12, c12, 0" : "=r" (reg));
- return reg;
- }
- static void mt_gic_icc_msre_write(void)
- {
- uint32_t reg;
- #define MON_MODE "#22"
- #define SVC_MODE "#19"
- /*
- * switch to monitor mode and mark ICC_MSRE.
- */
- __asm__ volatile("CPS " MON_MODE "\n"
- "MRC p15, 6, %0, c12, c12, 5\n"
- "ORR %0, %0, #9\n"
- "MCR p15, 6, %0, c12, c12, 5\n"
- "CPS " SVC_MODE "\n" : "=r" (reg));
- dsb();
- }
- static void mt_gic_icc_sre_write(uint32_t reg)
- {
- __asm__ volatile("MCR p15, 0, %0, c12, c12, 5" :: "r" (reg));
- dsb();
- }
- static uint32_t mt_gic_icc_sre_read(void)
- {
- uint32_t reg;
- __asm__ volatile("MRC p15, 0, %0, c12, c12, 5" : "=r" (reg));
- return reg;
- }
- static void mt_gic_icc_eoir1_write(uint32_t reg)
- {
- __asm__ volatile("MCR p15, 0, %0, c12, c12, 1" :: "r" (reg));
- }
- uint32_t mt_mpidr_read(void)
- {
- uint32_t reg;
- __asm__ volatile("MRC p15, 0, %0, c0, c0, 5" : "=r" (reg));
- return reg;
- }
- #ifdef GIC600
- /* GIC600-specific accessor functions */
- static void gicr_write_pwrr(uintptr_t base, unsigned int val)
- {
- DRV_WriteReg32(base + GICR_PWRR, val);
- }
- static uint32_t gicr_read_pwrr(uintptr_t base)
- {
- return DRV_Reg32(base + GICR_PWRR);
- }
- static void gic600_rdistif_init(void)
- {
- unsigned int rdist_base = GIC_REDIS_BASE;
- unsigned int ret;
- do {
- /* Check group not transitioning (polling for PWRR_RDGPO == PWRR_RDGPD) */
- ret = gicr_read_pwrr(rdist_base);
- while (((ret & PWRR_RDGPD) >> PWRR_RDGPD_SHIFT)
- != ((ret & PWRR_RDGPO) >> PWRR_RDGPO_SHIFT))
- ret = gicr_read_pwrr(rdist_base);
- /* Power on redistributor */
- gicr_write_pwrr(rdist_base, PWRR_ON);
- /* Keep retrying until the power on state is reflected (PWRR_RDGPO == 0)*/
- } while (gicr_read_pwrr(rdist_base) & PWRR_RDGPO);
- }
- #endif
- static void mt_gic_cpu_init(void)
- {
- mt_gic_icc_sre_write(0x01);
- mt_gic_icc_primask_write(0xF0);
- mt_gic_icc_igrpen1_write(0x01);
- dsb();
- }
- static void mt_gic_redist_init(void)
- {
- unsigned int value;
- #ifdef GIC600
- gic600_rdistif_init();
- #endif
- /* Wake up this CPU redistributor */
- value = DRV_Reg32(GIC_REDIS_BASE + GIC_REDIS_WAKER);
- value &= ~GICR_WAKER_ProcessorSleep;
- DRV_WriteReg32(GIC_REDIS_BASE + GIC_REDIS_WAKER, value);
- while (DRV_Reg32(GIC_REDIS_BASE + GIC_REDIS_WAKER) & GICR_WAKER_ChildrenAsleep);
- }
- static void mt_git_dist_rwp(void)
- {
- /*
- * check GICD_CTLR.RWP for done check
- */
- while (DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CTRL) & GICD_CTLR_RWP) {
- }
- }
- static void mt_gic_dist_init(void)
- {
- unsigned int i;
- uint64_t affinity;
- affinity = mt_irq_get_affinity();
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CTRL, GICD_CTLR_ARE);
- mt_git_dist_rwp();
- /*
- * Set all global interrupts to be level triggered, active low.
- */
- for (i = 32; i < (MT_NR_SPI + 32); i += 16) {
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CONFIG + i * 4 / 16, 0);
- }
- /*
- * Set all global interrupts to this CPU only.
- */
- for (i = 0; i < MT_NR_SPI; i++) {
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ROUTE + i * 8, (affinity & 0xFFFFFFFF));
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ROUTE + i * 8 + 4, (affinity >> 32));
- }
- /*
- * Set all interrupts to G1S. Leave the PPI and SGIs alone
- * as they are set by redistributor registers.
- */
- for (i = 0; i < NR_IRQ_LINE; i += 32)
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_IGRPMODR + i / 8, 0xFFFFFFFF);
- /*
- * Set priority on all interrupts.
- */
- for (i = 0; i < NR_IRQ_LINE; i += 4) {
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_PRI + i * 4 / 4, 0xA0A0A0A0);
- }
- /*
- * Disable all interrupts.
- */
- for (i = 0; i < NR_IRQ_LINE; i += 32) {
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + i * 4 / 32, 0xFFFFFFFF);
- }
- /*
- * Clear all active status
- */
- for (i = 0; i < NR_IRQ_LINE; i += 32) {
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ACTIVE_CLEAR + i * 4 / 32, 0xFFFFFFFF);
- }
- /*
- * Clear all pending status
- */
- for (i = 0; i < NR_IRQ_LINE; i += 32) {
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_PENDING_CLEAR + i * 4 / 32, 0xFFFFFFFF);
- }
- dsb();
- mt_git_dist_rwp();
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CTRL, GICD_CTLR_ARE | GICD_CTLR_ENGRP1S | GICD_CTLR_ENGRP1NS);
- mt_git_dist_rwp();
- }
- unsigned int gicd_read_iidr(unsigned int gicd_base)
- {
- return DRV_Reg32(gicd_base + GIC_DIST_IIDR);
- }
- void platform_init_interrupts(void)
- {
- uint32_t sec;
- sec = mt_interrupt_needed_for_secure();
- if (sec)
- mt_gic_icc_msre_write();
- mt_gic_dist_init();
- if (sec)
- mt_gic_redist_init();
- mt_gic_cpu_init();
- }
- void platform_deinit_interrupts(void)
- {
- unsigned int irq;
- for (irq = 0; irq < NR_IRQ_LINE; irq += 32) {
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + irq * 4 / 32, 0xFFFFFFFF);
- }
- dsb();
- while ((irq = mt_gic_icc_iar1_read()) != 1023 ) {
- mt_gic_icc_eoir1_write(irq);
- }
- }
- uint32_t mt_irq_get(void)
- {
- return mt_gic_icc_iar1_read();
- }
- #ifdef GIC600
- #ifdef MTK_INDIRECT_ACCESS_SUPPORT
- void mt_irq_set_mask(unsigned int irq)
- {
- unsigned int value;
- if (irq < GIC_PRIVATE_SIGNALS)
- return;
- /* set mask */
- value = 1;
- /* select spi id */
- value |= ((irq - GIC_PRIVATE_SIGNALS) << 16);
- /* select mask control */
- value |= (1 << 30);
- DRV_WriteReg32(INT_CFG_INDIRECT_ACCESS, value);
- dsb();
- }
- void mt_irq_set_unmask(unsigned int irq)
- {
- unsigned int value;
- if (irq < GIC_PRIVATE_SIGNALS)
- return;
- /* set unmask */
- value = 0;
- /* select spi id */
- value |= ((irq - GIC_PRIVATE_SIGNALS) << 16);
- /* select mask control */
- value |= (1 << 30);
- DRV_WriteReg32(INT_CFG_INDIRECT_ACCESS, value);
- dsb();
- }
- #else
- void mt_irq_set_mask(unsigned int irq)
- {
- unsigned int offset;
- unsigned int reg_index;
- unsigned int value;
- if (irq < GIC_PRIVATE_SIGNALS)
- return;
- offset = (irq - GIC_PRIVATE_SIGNALS) & 0x1F;
- reg_index = (irq - GIC_PRIVATE_SIGNALS) >> 5;
- value = DRV_Reg32(INT_MSK_CTL0 + (reg_index * 4));
- value |= (0x1 << offset);
- DRV_WriteReg32(INT_MSK_CTL0 + (reg_index * 4), value);
- dsb();
- }
- void mt_irq_set_unmask(unsigned int irq)
- {
- unsigned int offset;
- unsigned int reg_index;
- unsigned int value;
- if (irq < GIC_PRIVATE_SIGNALS)
- return;
- offset = (irq - GIC_PRIVATE_SIGNALS) & 0x1F;
- reg_index = (irq - GIC_PRIVATE_SIGNALS) >> 5;
- value = DRV_Reg32(INT_MSK_CTL0 + (reg_index * 4));
- value &= ~(0x1 << offset);
- DRV_WriteReg32(INT_MSK_CTL0 + (reg_index * 4), value);
- dsb();
- }
- #endif
- #endif
- void mt_irq_set_polarity(unsigned int irq, unsigned int polarity)
- {
- #ifndef MTK_POL_DEPRECATED
- unsigned int value;
- unsigned int result;
- #ifndef MTK_INDIRECT_ACCESS_SUPPORT
- unsigned int offset, reg_index;
- #endif
- // peripheral device's IRQ line is using GIC's SPI, and line ID >= GIC_PRIVATE_SIGNALS
- if (irq < GIC_PRIVATE_SIGNALS) {
- return;
- }
- #ifndef MTK_INDIRECT_ACCESS_SUPPORT
- offset = (irq - GIC_PRIVATE_SIGNALS) & 0x1F;
- reg_index = (irq - GIC_PRIVATE_SIGNALS) >> 5;
- if (polarity == 0) {
- value = DRV_Reg32(INT_POL_CTL0 + (reg_index * 4));
- value |= (1 << offset); // always invert the incoming IRQ's polarity
- DRV_WriteReg32((INT_POL_CTL0 + (reg_index * 4)), value);
- } else {
- value = DRV_Reg32(INT_POL_CTL0 + (reg_index * 4));
- value &= ~(0x1 << offset);
- DRV_WriteReg32(INT_POL_CTL0 + (reg_index * 4), value);
- }
- #else
- if (polarity == 0)
- value = 1; /* active low */
- else
- value = 0; /* active high */
- /* select spi id */
- value |= ((irq - GIC_PRIVATE_SIGNALS) << 16);
- /* select mask control*/
- value |= (1 << 29);
- DRV_WriteReg32(INT_CFG_INDIRECT_ACCESS, value);
- #endif
- #ifdef GIC600
- result = gicd_read_iidr(GIC_DIST_BASE);
- /* unmask irq for gic600 */
- if ((result >> GICD_V3_IIDR_PROD_ID) == GICD_V3_IIDR_GIC600)
- mt_irq_set_unmask(irq);
- #endif
- #endif //MTK_POL_DEPRECATED
- }
- void mt_irq_set_sens(unsigned int irq, unsigned int sens)
- {
- unsigned int config;
- if (sens == MT65xx_EDGE_SENSITIVE) {
- config = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
- config |= (0x2 << (irq % 16) * 2);
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
- } else {
- config = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
- config &= ~(0x2 << (irq % 16) * 2);
- DRV_WriteReg32( GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
- }
- dsb();
- }
- /*
- * mt_irq_mask: mask one IRQ
- * @irq: IRQ line of the IRQ to mask
- */
- void mt_irq_mask(unsigned int irq)
- {
- unsigned int mask = 1 << (irq % 32);
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + irq / 32 * 4, mask);
- dsb();
- }
- /*
- * mt_irq_unmask: unmask one IRQ
- * @irq: IRQ line of the IRQ to unmask
- */
- void mt_irq_unmask(unsigned int irq)
- {
- unsigned int mask = 1 << (irq % 32);
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + irq / 32 * 4, mask);
- dsb();
- }
- /*
- * mt_irq_ack: ack IRQ
- * @irq: IRQ line of the IRQ to mask
- */
- void mt_irq_ack(unsigned int irq)
- {
- mt_gic_icc_eoir1_write(irq);
- dsb();
- }
- /*
- * mt_irq_mask_all: mask all IRQ lines. (This is ONLY used for the sleep driver)
- * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
- * Return 0 for success; return negative values for failure.
- */
- int mt_irq_mask_all(struct mtk_irq_mask *mask)
- {
- unsigned int i;
- if (mask) {
- for (i = 0; i < IRQ_REGS; i++) {
- mask->mask[i] = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + i * 4);
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + i * 4, 0xFFFFFFFF);
- }
- dsb();
- mask->header = IRQ_MASK_HEADER;
- mask->footer = IRQ_MASK_FOOTER;
- return 0;
- } else {
- return -1;
- }
- }
- /*
- * mt_irq_mask_restore: restore all IRQ lines' masks. (This is ONLY used for the sleep driver)
- * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
- * Return 0 for success; return negative values for failure.
- */
- int mt_irq_mask_restore(struct mtk_irq_mask *mask)
- {
- unsigned int i;
- if (!mask) {
- return -1;
- }
- if (mask->header != IRQ_MASK_HEADER) {
- return -1;
- }
- if (mask->footer != IRQ_MASK_FOOTER) {
- return -1;
- }
- for (i = 0; i < IRQ_REGS; i++) {
- DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + i * 4, mask->mask[i]);
- }
- dsb();
- return 0;
- }
- void mt_irq_register_dump(void)
- {
- int i;
- uint32_t reg, reg2;
- dprintf(CRITICAL, "%s(): do irq register dump\n", __func__);
- reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CTRL);
- dprintf(CRITICAL, "GICD_CTLR: 0x%08x\n", reg);
- for (i = 0; i < MT_NR_SPI; i++) {
- reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ROUTE + i * 8);
- reg2 = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ROUTE + i * 8 + 4);
- dprintf(CRITICAL, "GICD_IROUTER[%d]: 0x%08x, 0x%08x\n", i, reg, reg2);
- }
- for (i = 0; i < NR_IRQ_LINE; i += 32) {
- reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_IGRPMODR + i / 8);
- dprintf(CRITICAL, "GICD_IGRPMODR[%d]: 0x%08x\n", i >> 5, reg);
- }
- for (i = 0; i < NR_IRQ_LINE; i += 4) {
- reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_PRI + i * 4 / 4);
- dprintf(CRITICAL, "GICD_IPRIORITYR[%d]: 0x%08x\n", i >> 2, reg);
- }
- for (i = 32; i < (MT_NR_SPI + 32); i += 16) {
- reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + i * 4 / 16);
- dprintf(CRITICAL, "DIST_ICFGR[%d]: 0x%08x\n", (i >> 4) - 2, reg);
- }
- for (i = 0; i < IRQ_REGS; i++) {
- reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + i * 4);
- dprintf(CRITICAL, "GICD_ISENABLER[%d]: 0x%08x\n", i, reg);
- }
- for (i = 0; i < IRQ_REGS; i++) {
- reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_PENDING_SET + i * 4);
- dprintf(CRITICAL, "GICD_ISPENDR[%d]: 0x%08x\n", i, reg);
- }
- for (i = 0; i < IRQ_REGS; i++) {
- reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ACTIVE_SET + i * 4);
- dprintf(CRITICAL, "GICD_ISACTIVER[%d]: 0x%08x\n", i, reg);
- }
- reg = mt_gic_icc_sre_read();
- dprintf(CRITICAL, "ICC_SRE: 0x%08x\n", reg);
- reg = mt_gic_icc_primask_read();
- dprintf(CRITICAL, "ICC_PMR: 0x%08x\n", reg);
- reg = mt_gic_icc_igrpen1_read();
- dprintf(CRITICAL, "ICC_IGRPEN1: 0x%08x\n", reg);
- reg = mt_gic_icc_iar1_read();
- dprintf(CRITICAL, "ICC_IAR1: 0x%08x\n", reg);
- reg = mt_mpidr_read();
- dprintf(CRITICAL, "MPIDR: 0x%08x\n", reg);
- }
|