| /* |
| * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * Redistributions of source code must retain the above copyright notice, this |
| * list of conditions and the following disclaimer. |
| * |
| * Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * Neither the name of ARM nor the names of its contributors may be used |
| * to endorse or promote products derived from this software without specific |
| * prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| #include <arch_helpers.h> |
| #include <drivers/arm/gic_common.h> |
| #include <drivers/arm/gicv2.h> |
| #include <bl31/interrupt_mgmt.h> |
| #include <common/bl_common.h> |
| #include <mt8516_def.h> |
| #include <platform_def.h> |
| #include <lib/mmio.h> |
| #include <common/debug.h> |
| #include <plat/common/platform.h> |
| |
| void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val); |
| |
| const unsigned int mt_irq_sec_array[] = { |
| MT_IRQ_SEC_SGI_0, |
| MT_IRQ_SEC_SGI_1, |
| MT_IRQ_SEC_SGI_2, |
| MT_IRQ_SEC_SGI_3, |
| MT_IRQ_SEC_SGI_4, |
| MT_IRQ_SEC_SGI_5, |
| MT_IRQ_SEC_SGI_6, |
| MT_IRQ_SEC_SGI_7, |
| // WDT_IRQ_BIT_ID, |
| }; |
| |
| gicv2_driver_data_t mt_gic_data = { |
| .gicd_base = BASE_GICD_BASE, |
| .gicc_base = BASE_GICC_BASE, |
| // .g0_interrupt_num = ARRAY_SIZE(mt_irq_sec_array), |
| // .g0_interrupt_array = mt_irq_sec_array, |
| }; |
| |
| #if 1 |
| static inline void gicd_write_ctlr(uintptr_t base, unsigned int val) |
| { |
| mmio_write_32(base + GICD_CTLR, val); |
| } |
| |
| static inline unsigned int gicd_read_ctlr(uintptr_t base) |
| { |
| return mmio_read_32(base + GICD_CTLR); |
| } |
| #endif |
| |
| static inline unsigned int gicd_read_typer(uintptr_t base) |
| { |
| return mmio_read_32(base + GICD_TYPER); |
| } |
| |
| #if 0 |
| static inline unsigned int gicd_read_sgir(uintptr_t base) |
| { |
| return mmio_read_32(base + GICD_SGIR); |
| } |
| |
| static inline void gicd_write_sgir(uintptr_t base, unsigned int val) |
| { |
| mmio_write_32(base + GICD_SGIR, val); |
| } |
| #endif |
| |
| /****************************************************************************** |
| * ARM common helper to initialize the GICv2 only driver. |
| *****************************************************************************/ |
| void plat_mt_gic_driver_init(void) |
| { |
| gicv2_driver_init(&mt_gic_data); |
| } |
| |
| void plat_mt_gic_init(void) |
| { |
| int idx; |
| |
| gicv2_distif_init(); |
| gicv2_pcpu_distif_init(); |
| gicv2_cpuif_enable(); |
| |
| /* set WDT interrupt as falling edge trigger */ |
| gicd_write_icfgr(BASE_GICD_BASE, WDT_IRQ_BIT_ID, |
| 0x2<<((WDT_IRQ_BIT_ID%16)*2)); |
| |
| /* set pol control as non-secure */ |
| for (idx=0;idx<INT_POL_SECCTL_NUM;idx++) |
| mmio_write_32(INT_POL_SECCTL0+idx*4, 0); |
| } |
| |
| /* from gicv2_private.h */ |
| static inline unsigned int gicc_read_ctlr(uintptr_t base) |
| { |
| return mmio_read_32(base + GICC_CTLR); |
| } |
| |
| static inline void gicc_write_ctlr(uintptr_t base, unsigned int val) |
| { |
| mmio_write_32(base + GICC_CTLR, val); |
| } |
| |
| static inline void gicd_write_sgir(uintptr_t base, unsigned int val) |
| { |
| mmio_write_32(base + GICD_SGIR, val); |
| } |
| |
| void irq_raise_softirq(unsigned int map, unsigned int irq) |
| { |
| int satt; |
| |
| satt = 1 << 15; |
| |
| if(plat_ic_get_interrupt_type(irq) == INTR_TYPE_S_EL1) |
| { |
| satt = 0; |
| } |
| |
| gicd_write_sgir(BASE_GICD_BASE, (map << 16) | satt | irq); |
| |
| dsb(); |
| } |
| |
| #ifndef MAX_GIC_NR |
| #define MAX_GIC_NR (1) |
| #endif |
| #define MAX_RDIST_NR (64) |
| #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) |
| |
| /* For saving ATF size, we reduce 1020 -> 320 */ |
| struct gic_chip_data { |
| unsigned int saved_spi_enable[DIV_ROUND_UP(320, 32)]; |
| unsigned int saved_spi_conf[DIV_ROUND_UP(320, 16)]; |
| unsigned int saved_spi_target[DIV_ROUND_UP(320, 4)]; |
| unsigned int saved_spi_group[DIV_ROUND_UP(320, 32)]; |
| }; |
| static struct gic_chip_data gic_data[MAX_GIC_NR]; |
| |
| /* TODO: check all registers to save */ |
| void mt_gic_dist_save(void) |
| { |
| unsigned int gic_irqs; |
| unsigned int dist_base; |
| int i; |
| |
| /* TODO: pending bit MUST added */ |
| dist_base = BASE_GICD_BASE; |
| |
| gic_irqs = 32 * ((gicd_read_typer(dist_base) & TYPER_IT_LINES_NO_MASK) + 1); |
| |
| for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++) |
| gic_data[0].saved_spi_conf[i] = |
| mmio_read_32(dist_base + GICD_ICFGR + i * 4); |
| |
| for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++) |
| gic_data[0].saved_spi_target[i] = |
| mmio_read_32(dist_base + GICD_ITARGETSR + i * 4); |
| |
| for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) |
| gic_data[0].saved_spi_enable[i] = |
| mmio_read_32(dist_base + GICD_ISENABLER + i * 4); |
| |
| for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) |
| gic_data[0].saved_spi_group[i] = |
| mmio_read_32(dist_base + GICD_IGROUPR + i * 4); |
| } |
| |
| /* TODO: check all registers to restore */ |
| void mt_gic_dist_restore(void) |
| { |
| unsigned int gic_irqs; |
| unsigned int dist_base; |
| unsigned int ctlr; |
| int i; |
| |
| dist_base = BASE_GICD_BASE; |
| |
| gic_irqs = 32 * ((gicd_read_typer(dist_base) & TYPER_IT_LINES_NO_MASK) + 1); |
| |
| /* Disable the distributor before going further */ |
| ctlr = gicd_read_ctlr(dist_base); |
| ctlr &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT); |
| gicd_write_ctlr(dist_base, ctlr); |
| |
| for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++) |
| mmio_write_32(dist_base + GICD_ICFGR + i * 4, gic_data[0].saved_spi_conf[i]); |
| |
| for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++) |
| mmio_write_32(dist_base + GICD_ITARGETSR + i * 4, gic_data[0].saved_spi_target[i]); |
| |
| for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) |
| mmio_write_32(dist_base + GICD_ISENABLER + i * 4, gic_data[0].saved_spi_enable[i]); |
| |
| for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) |
| mmio_write_32(dist_base + GICD_IGROUPR + i * 4, gic_data[0].saved_spi_group[i]); |
| |
| gicd_write_ctlr(dist_base, ctlr | CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT); |
| } |
| |
| void mt_gic_cpuif_setup(void) |
| { |
| unsigned int val = gicc_read_ctlr(BASE_GICC_BASE); |
| |
| val |= CTLR_ENABLE_G1_BIT; |
| gicc_write_ctlr(BASE_GICC_BASE, val); |
| } |