| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- /**
- * \file
- *
- * Implementation of Ark Interrupt Controller (AIC) controller.
- *
- */
- /*----------------------------------------------------------------------------
- * Headers
- *----------------------------------------------------------------------------*/
- #include "FreeRTOS.h"
- #include "chip.h"
- #include <stdint.h>
- #include <assert.h>
- #include <string.h>
- #define GICD_DIST_BASE (REGS_GIC_BASE+0x1000)
- #define GICC_CPU_BASE (REGS_GIC_BASE+0x2000)
- //#define GICD_CTLR *((volatile unsigned int *)(GICD_DIST_BASE+ 0x00))
- //#define GICD_TYPER *((volatile unsigned int *)(GICD_DIST_BASE+ 0x04))
- //#define GICD_IIDR *((volatile unsigned int *)(GICD_DIST_BASE+ 0x08))
- //#define GICD_IGROUPR *((volatile unsigned int *)(GICD_DIST_BASE+ 0x80))
- #define GICD_ISENABLER0 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x100))
- #define GICD_ISENABLER1 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x104))
- #define GICD_ISENABLER2 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x108))
- //#define GICD_ISENABLER3 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x10C))
- #define GICD_ICENABLER0 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x180))
- #define GICD_ICENABLER1 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x184))
- #define GICD_ICENABLER2 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x188))
- //#define GICD_ICENABLER3 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x18c))
- #define GICD_ISPENDR0 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x200))
- #define GICD_ISPENDR1 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x204))
- #define GICD_ISPENDR2 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x208))
- //#define GICD_ISPENDR3 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x20C))
- #define GICD_ICPENDR0 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x280))
- #define GICD_ICPENDR1 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x284))
- #define GICD_ICPENDR2 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x288))
- //#define GICD_ICPENDR3 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x28C))
- #define GICD_ISACTIVER0 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x300))
- #define GICD_ISACTIVER1 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x304))
- #define GICD_ISACTIVER2 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x308))
- //#define GICD_ISACTIVER3 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x30C))
- #define GICD_ICACTIVER0 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x380))
- #define GICD_ICACTIVER1 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x384))
- #define GICD_ICACTIVER2 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x388))
- //#define GICD_ICACTIVER3 *((volatile unsigned int *)(GICD_DIST_BASE+ 0x38C))
- #define GIC_CPU_CTRL 0x00
- #define GIC_CPU_PRIMASK 0x04
- #define GIC_CPU_BINPOINT 0x08
- #define GIC_CPU_INTACK 0x0c
- #define GIC_CPU_EOI 0x10
- #define GIC_CPU_RUNNINGPRI 0x14
- #define GIC_CPU_HIGHPRI 0x18
- #define GIC_CPU_ALIAS_BINPOINT 0x1c
- #define GIC_CPU_ACTIVEPRIO 0xd0
- #define GIC_CPU_IDENT 0xfc
- #define GICC_ENABLE 0x1
- #define GICC_INT_PRI_THRESHOLD 0xf0
- #define GICC_IAR_INT_ID_MASK 0x3ff
- #define GICC_INT_SPURIOUS 1023
- #define GICC_DIS_BYPASS_MASK 0x1e0
- #define GIC_DIST_CTRL 0x000
- #define GIC_DIST_TYPER 0x004
- #define GIC_DIST_IGROUP 0x080
- #define GIC_DIST_ENABLE_SET 0x100
- #define GIC_DIST_ENABLE_CLEAR 0x180
- #define GIC_DIST_PENDING_SET 0x200
- #define GIC_DIST_PENDING_CLEAR 0x280
- #define GIC_DIST_ACTIVE_SET 0x300
- #define GIC_DIST_ACTIVE_CLEAR 0x380
- #define GIC_DIST_PRI 0x400
- #define GIC_DIST_TARGET 0x800
- #define GIC_DIST_CONFIG 0xc00
- #define GIC_DIST_SOFTINT 0xf00
- #define GIC_DIST_SGI_PENDING_CLEAR 0xf10
- #define GIC_DIST_SGI_PENDING_SET 0xf20
- #define GICD_ENABLE 0x1
- #define GICD_DISABLE 0x0
- #define GICD_INT_ACTLOW_LVLTRIG 0x0
- #define GICD_INT_EN_CLR_X32 0xffffffff
- #define GICD_INT_EN_SET_SGI 0x0000ffff
- #define GICD_INT_EN_CLR_PPI 0xffff0000
- #define GICD_INT_DEF_PRI 0xa0
- #define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\
- (GICD_INT_DEF_PRI << 16) |\
- (GICD_INT_DEF_PRI << 8) |\
- GICD_INT_DEF_PRI)
- #define GICH_HCR 0x0
- #define GICH_VTR 0x4
- #define GICH_VMCR 0x8
- #define GICH_MISR 0x10
- #define GICH_EISR0 0x20
- #define GICH_EISR1 0x24
- #define GICH_ELRSR0 0x30
- #define GICH_ELRSR1 0x34
- #define GICH_APR 0xf0
- #define GICH_LR0 0x100
- #define GICH_HCR_EN (1 << 0)
- #define GICH_HCR_UIE (1 << 1)
- #define GICH_LR_VIRTUALID (0x3ff << 0)
- #define GICH_LR_PHYSID_CPUID_SHIFT (10)
- #define GICH_LR_PHYSID_CPUID (7 << GICH_LR_PHYSID_CPUID_SHIFT)
- #define GICH_LR_STATE (3 << 28)
- #define GICH_LR_PENDING_BIT (1 << 28)
- #define GICH_LR_ACTIVE_BIT (1 << 29)
- #define GICH_LR_EOI (1 << 19)
- #define GICH_VMCR_CTRL_SHIFT 0
- #define GICH_VMCR_CTRL_MASK (0x21f << GICH_VMCR_CTRL_SHIFT)
- #define GICH_VMCR_PRIMASK_SHIFT 27
- #define GICH_VMCR_PRIMASK_MASK (0x1f << GICH_VMCR_PRIMASK_SHIFT)
- #define GICH_VMCR_BINPOINT_SHIFT 21
- #define GICH_VMCR_BINPOINT_MASK (0x7 << GICH_VMCR_BINPOINT_SHIFT)
- #define GICH_VMCR_ALIAS_BINPOINT_SHIFT 18
- #define GICH_VMCR_ALIAS_BINPOINT_MASK (0x7 << GICH_VMCR_ALIAS_BINPOINT_SHIFT)
- #define IRQ_TYPE_LEVEL_HIGH (0x4)
- #define IRQ_TYPE_LEVEL_LOW (0x8)
- #define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
- #define IRQ_TYPE_LEVEL_MASK (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)
- #define ICSET 0x00
- #define ICPEND 0x04
- #define ICMODE 0x08
- #define ICMASK 0x0C
- #define ICLEVEL 0x10
- #define IRQISPR 0x3C
- #define IRQISPC 0x40
- #define IVEC_ADDR 0x78
- #define NR_GIC_CPU_IF 1
- #define MAX_IRQ_NUM 160
- typedef struct {
- ISRFunction_t handler;
- void *handler_param;
- }IrqDesc_t;
- static int gic_set_type(unsigned int irq, unsigned int type);
- static IrqDesc_t irq_descs[MAX_IRQ_NUM];
- static unsigned char gic_cpu_map[NR_GIC_CPU_IF];
- static volatile uint8_t interrupt_nest = 0;
- void gicd_Interrupt_disable(unsigned int irq)
- {
- if(irq<16)
- return;
- if(irq<31)
- {
- GICD_ICENABLER0|=(1<<irq) ;
- }
- else if(irq<63)
- {
- GICD_ICENABLER1|=~(1<<(irq-32));
- }
- else if(irq<95)
- {
- GICD_ICENABLER2|=~(1<<(irq-64));
- }
- }
- void gicd_Interrupt_enable(unsigned int irq)
- {
- if(irq<16)
- return;
- if(irq<=31)
- {
- GICD_ISENABLER0 |=(1<<irq) ;
- }
- else if(irq<=63)
- {
- GICD_ISENABLER1 |=(1<<(irq-32));
- }
- else if(irq<=95)
- {
- GICD_ISENABLER2 |=(1<<(irq-64));
- }
- }
- void gicd_Pending_disable(unsigned int irq)
- {
- if(irq<31)
- {
- GICD_ICPENDR0|=(1<<irq) ;
- }
- else if(irq<63)
- {
- GICD_ICPENDR1|=(1<<(irq-32));
- }
- else if(irq<95)
- {
- GICD_ICPENDR2|=(1<<(irq-64));
- }
- }
- void gicd_Pending_enable(unsigned int irq)
- {
- if(irq<31)
- {
- GICD_ISPENDR0 |=(1<<irq) ;
- }
- else if(irq<63)
- {
- GICD_ISPENDR1 |=(1<<(irq-32));
- }
- else if(irq<95)
- {
- GICD_ISPENDR2 |=(1<<(irq-64));
- }
- }
- void gicd_Active_enable(unsigned int irq)
- {
- if(irq<31)
- {
- GICD_ISACTIVER0|=(1<<irq) ;
- }
- else if(irq<63)
- {
- GICD_ISACTIVER1 |=(1<<(irq-32));
- }
- else if(irq<95)
- {
- GICD_ISACTIVER2 |=(1<<(irq-64));
- }
- }
- void gicd_Active_disable(unsigned int irq)
- {
- if(irq<=31)
- {
- GICD_ICACTIVER0|=(1<<irq) ;
- }
- else if(irq<=63)
- {
- GICD_ICACTIVER1|=(1<<(irq-32));
- }
- else if(irq<=95)
- {
- GICD_ICACTIVER2 |=(1<<(irq-64));
- }
- }
- void gic_set_pri(unsigned int irq,unsigned char pri)
- {
- unsigned int regoff=0;
- unsigned int byteoff = 0;
- unsigned int val=0;
- regoff = irq/4;
- byteoff = irq%4;
- val=readl(GICD_DIST_BASE+GIC_DIST_PRI+(regoff*4));
- val &=~(0xFF<<(byteoff*8));
- val |=(pri<<(byteoff*8));
- writel(val,(GICD_DIST_BASE+GIC_DIST_PRI+(regoff*4)));
- }
- int32_t request_irq(uint32_t irq_source, int32_t priority,ISRFunction_t func, void *param)
- {
- unsigned char type = IRQ_TYPE_LEVEL_HIGH;
- if(func == NULL)
- return -1;
- else if(irq_source >= 32)
- {
- portENTER_CRITICAL();
- gic_set_pri(irq_source,priority);
- if((type == IRQ_TYPE_LEVEL_HIGH )|| (type ==IRQ_TYPE_EDGE_RISING) )
- gic_set_type(irq_source,type);
- gicd_Interrupt_enable(irq_source);
- irq_descs[irq_source].handler = func;
- irq_descs[irq_source].handler_param = param;
- portEXIT_CRITICAL();
- }
- return 0;
- }
- int32_t free_irq(uint32_t irq_source)
- {
- if (irq_source > MAX_IRQ_NUM ) {
- return -1;
- }
- portENTER_CRITICAL();
- irq_descs[irq_source].handler = NULL;
- irq_descs[irq_source].handler_param = NULL;
- gicd_Active_disable(irq_source);
- portEXIT_CRITICAL();
- return 0;
- }
- void GIC_IrqHandler(void)
- {
- unsigned int irqstat, irqnr;
- interrupt_nest++;
- do {
- irqstat = readl(GICC_CPU_BASE+ GIC_CPU_INTACK);
- irqnr = irqstat & GICC_IAR_INT_ID_MASK;
- if (irqnr > 15 && irqnr < 1021)
- {
- if (irq_descs[irqnr].handler)
- irq_descs[irqnr].handler(irq_descs[irqnr].handler_param);
- writel(irqstat, GICC_CPU_BASE+ GIC_CPU_EOI);
- gicd_Active_disable(irqnr);
- continue;
- }
- if (irqnr < 16) {
- writel(irqstat, GICC_CPU_BASE+ GIC_CPU_EOI);
- continue;
- }
- break;
- } while (0);
- interrupt_nest--;
- }
- int gic_configure_irq(unsigned int irq, unsigned int type)
- {
- unsigned int enablemask = 1 << (irq % 32);
- unsigned int enableoff = (irq / 32) * 4;
- unsigned int confmask = 0x2 << ((irq % 16) * 2);
- unsigned int confoff = (irq / 16) * 4;
- unsigned char enabled = 0;
- unsigned int val, oldval;
- int ret = 0;
- /*
- * Read current configuration register, and insert the config
- * for "irq", depending on "type".
- */
- val = oldval = readl(GICD_DIST_BASE+ GIC_DIST_CONFIG + confoff);
- if (type & IRQ_TYPE_LEVEL_MASK)
- val &= ~confmask;
- else if (type & IRQ_TYPE_EDGE_BOTH)
- val |= confmask;
- /*
- * As recommended by the spec, disable the interrupt before changing
- * the configuration
- */
- if (readl(GICD_DIST_BASE+ GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
- writel(enablemask, GICD_DIST_BASE+ GIC_DIST_ENABLE_CLEAR + enableoff);
- enabled = 1;
- }
- /*
- * Write back the new configuration, and possibly re-enable
- * the interrupt. If we tried to write a new configuration and failed,
- * return an error.
- */
- writel(val, GICD_DIST_BASE+ GIC_DIST_CONFIG + confoff);
- if (readl(GICD_DIST_BASE+ GIC_DIST_CONFIG + confoff) != val && val != oldval)
- ret = -1;
- if (enabled)
- writel(enablemask, GICD_DIST_BASE+ GIC_DIST_ENABLE_SET + enableoff);
- return ret;
- }
- #if 0
- static void gic_mask_irq(unsigned int irq)
- {
- unsigned int mask = 1 << (irq % 32);
- //unsigned long flags;
- writel(mask, GICD_DIST_BASE+ GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4);
- }
- static void gic_unmask_irq(unsigned int irq)
- {
- unsigned int mask = 1 << (irq % 32);
- //unsigned long flags;
- writel(mask, GICD_DIST_BASE+ GIC_DIST_ENABLE_SET + (irq / 32) * 4);
- }
- static void gic_eoi_irq(unsigned int irq )
- {
- writel(irq, GICC_CPU_BASE+ GIC_CPU_EOI);
- }
- #endif
- static int gic_set_type(unsigned int irq, unsigned int type)
- {
- unsigned int gicirq = irq;
- // unsigned long flags;
- int ret;
- /* Interrupt configuration for SGIs can't be changed */
- if (gicirq < 16)
- return -1;
- /* SPIs have restrictions on the supported types */
- if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
- type != IRQ_TYPE_EDGE_RISING)
- return -1;
- // if (gic_arch_extn.irq_set_type)
- // gic_arch_extn.irq_set_type(d, type);
- ret = gic_configure_irq(gicirq, type);
- return ret;
- }
- void gic_dist_config(int gic_irqs)
- {
- unsigned int i;
- /*
- * Set all global interrupts to be level triggered, active low.
- */
- for (i = 32; i < gic_irqs; i += 16)
- writel(GICD_INT_ACTLOW_LVLTRIG,
- GICD_DIST_BASE+ GIC_DIST_CONFIG + i / 4);
- /*
- * Set priority on all global interrupts.
- */
- for (i = 32; i < gic_irqs; i += 4)
- writel(GICD_INT_DEF_PRI_X4, GICD_DIST_BASE+ GIC_DIST_PRI + i);
- /*
- * Disable all interrupts. Leave the PPI and SGIs alone
- * as they are enabled by redistributor registers.
- */
- for (i = 32; i < gic_irqs; i += 32)
- writel(GICD_INT_EN_CLR_X32,
- GICD_DIST_BASE+ GIC_DIST_ENABLE_CLEAR + i / 8);
- }
- static unsigned char gic_get_cpumask(void)
- {
- unsigned int mask, i;
- for (i = mask = 0; i < 32; i += 4) {
- mask = readl(GICD_DIST_BASE+ GIC_DIST_TARGET + i);
- mask |= mask >> 16;
- mask |= mask >> 8;
- if (mask)
- break;
- }
- // if (!mask)
- // printf("GIC CPU mask not found - kernel will fail to boot.\n");
- return mask;
- }
- static void gic_dist_init(void)
- {
- unsigned int i;
- unsigned int cpumask;
- unsigned int gic_irqs = 96;
- writel(GICD_DISABLE, GICD_DIST_BASE+ GIC_DIST_CTRL);
- /*
- * Set all global interrupts to this CPU only.
- */
- cpumask = gic_get_cpumask();
- cpumask |= cpumask << 8;
- cpumask |= cpumask << 16;
- for (i = 32; i < gic_irqs; i += 4)
- writel(cpumask, GICD_DIST_BASE+ GIC_DIST_TARGET + i * 4 / 4);
- gic_dist_config(gic_irqs);
- writel(GICD_ENABLE, GICD_DIST_BASE+ GIC_DIST_CTRL);
- }
- void gic_cpu_config(void)
- {
- int i;
- /*
- * Deal with the banked PPI and SGI interrupts - disable all
- * PPI interrupts, ensure all SGI interrupts are enabled.
- */
- writel(GICD_INT_EN_CLR_PPI, GICD_DIST_BASE+ GIC_DIST_ENABLE_CLEAR);
- writel(GICD_INT_EN_SET_SGI, GICD_DIST_BASE+ GIC_DIST_ENABLE_SET);
- /*
- * Set priority on PPI and SGI interrupts
- */
- for (i = 0; i < 32; i += 4)
- writel(GICD_INT_DEF_PRI_X4,
- GICD_DIST_BASE+ GIC_DIST_PRI + i * 4 / 4);
- }
- static void gic_cpu_if_up(void)
- {
- unsigned int bypass = 0;
- /*
- * Preserve bypass disable bits to be written back later
- */
- bypass = readl(GICC_CPU_BASE+ GIC_CPU_CTRL);
- bypass &= GICC_DIS_BYPASS_MASK;
- writel(bypass | GICC_ENABLE, GICC_CPU_BASE+ GIC_CPU_CTRL);
- }
- void gic_cpu_if_down(void)
- {
- unsigned int val = 0;
- val = readl(GICC_CPU_BASE+ GIC_CPU_CTRL);
- val &= ~GICC_ENABLE;
- writel(val, GICC_CPU_BASE+ GIC_CPU_CTRL);
- }
- static void gic_cpu_init(void)
- {
- unsigned int cpu_mask, cpu = 0;
- int i;
- /*
- * Get what the GIC says our CPU mask is.
- */
- // if(cpu >= NR_GIC_CPU_IF);
- // return;
- cpu_mask = gic_get_cpumask();
- gic_cpu_map[cpu] = cpu_mask;
- /*
- * Clear our mask from the other map entries in case they're
- * still undefined.
- */
- for (i = 0; i < NR_GIC_CPU_IF; i++)
- if (i != cpu)
- gic_cpu_map[i] &= ~cpu_mask;
- gic_cpu_config();
- writel(GICC_INT_PRI_THRESHOLD, GICC_CPU_BASE+ GIC_CPU_PRIMASK);
- gic_cpu_if_up();
- }
- void GIC_Initialize(void)
- {
- int gic_irqs, i;
- /*
- * Initialize the CPU interface map to all CPUs.
- * It will be refined as each CPU probes its ID.
- */
- for (i = 0; i < NR_GIC_CPU_IF; i++)
- gic_cpu_map[i] = 0xff;
- /*
- * Find out how many interrupts are supported.
- * The GIC only supports up to 1020 interrupt sources.
- */
- gic_irqs = readl(GICD_DIST_BASE+ GIC_DIST_TYPER) & 0x1f;
- gic_irqs = (gic_irqs + 1) * 32;
- if (gic_irqs > 1020)
- gic_irqs = 1020;
- for(i=0;i<gic_irqs;i++)
- irq_descs[i].handler = NULL;
- gic_dist_init();
- gic_cpu_init();
- }
- uint8_t interrupt_get_nest(void)
- {
- uint8_t ret;
- UBaseType_t uxSavedInterruptStatus;
- uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
- ret = interrupt_nest;
- portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
- return ret;
- }
|