blob: 2d59496c1edf797cadcabe2e0de4b304c89c6876 [file] [log] [blame]
/*
* 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);
}