aos/kernel/arch/arm/gic.c
Daniel Schwyn a7a01f8ea1 Bug fixes
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-04-04 15:16:17 +02:00

274 lines
7.7 KiB
C

/*
* Copyright (c) 2012, ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
*/
#include <kernel.h>
#include <dev/pl390_gic_cpuif_dev.h>
#include <dev/pl390_gic_dist_dev.h>
#include <arch/arm/gic.h>
#include <arch/arm/platform.h>
#include <paging_kernel_arch.h>
#include <irq.h>
#include <getopt/getopt.h>
static pl390_gic_cpuif_t gic;
static pl390_gic_dist_t gic_dist;
#define MSG(format, ...) printk( LOG_NOTE, "GIC: "format, ## __VA_ARGS__ )
extern lpaddr_t platform_gic_cpu_interface_base;
extern lpaddr_t platform_gic_distributor_base;
// Command line arguments
static struct cmdarg cmdargs[] = {
{"gic", ArgType_UInt, { .uinteger = &platform_gic_cpu_interface_base }},
{"gicdist", ArgType_UInt, { .uinteger = &platform_gic_distributor_base }},
{NULL, 0, {NULL}}
};
enum IrqType {
IrqType_SGI,
IrqType_PPI,
IrqType_SPI
};
#define CPU_SIZE 0x1000
#define DIST_SIZE 0x1000
/**
* \brief Returns the IRQ type based on the interrupt ID
*
* We have three types of interrupts
* 1) Software generated Interrupts (SGI): IDs 0-15
* 2) Private Peripheral Interrupts (PPI): IDs 16-31
* 3) Shared Peripheral Interrups (SPI): IDs 32-
*
* \return The type of the interrupt.
*/
static enum IrqType get_irq_type(uint32_t int_id)
{
if (int_id < 16) {
return IrqType_SGI;
} else if (int_id < 32) {
return IrqType_PPI;
} else {
return IrqType_SPI;
}
}
/*
* Initialize the global interrupt controller
*
* There are three types of interrupts
* 1) Software generated Interrupts (SGI) - IDs 0-15
* 2) Private Peripheral Interrupts (PPI) - IDs 16-31
* 3) Shared Peripheral Interrups (SPI) - IDs 32...
*/
void gic_init(void)
{
parse_commandline(kernel_command_line, cmdargs);
printk(LOG_NOTE, "GICv1: Initializing. cpu_if=%p, dist=%p\n",
platform_gic_cpu_interface_base, platform_gic_distributor_base);
lvaddr_t gic_cpu_base =
paging_map_device(platform_gic_cpu_interface_base, CPU_SIZE );
pl390_gic_cpuif_initialize(&gic, (mackerel_addr_t)gic_cpu_base );
lvaddr_t gic_dist_base =
paging_map_device(platform_gic_distributor_base, DIST_SIZE );
pl390_gic_dist_initialize(&gic_dist, (mackerel_addr_t)gic_dist_base );
// set priority mask of cpu interface, currently set to lowest priority
// to accept all interrupts
pl390_gic_cpuif_ICCPMR_wr(&gic, 0xff);
// set binary point to define split of group- and subpriority
// currently we allow for 8 subpriorities
pl390_gic_cpuif_ICCBPR_wr(&gic, 0x2);
// enable interrupt forwarding to processor
pl390_gic_cpuif_ICCICR_enable_wrf(&gic, 0x1);
MSG("gic_init done\n");
}
void __attribute__((noreturn)) gic_disable_all_irqs(void)
{
panic("gic_disable_all_irqs NYI for armv7");
// XXX Rewrite according to pl390 interface changes!
// ALSO remove noreturn option
/* //disable PPI interrupts */
/* pl390_gic_cpuif_PPI_ICDICER_wr(&gic, (uint16_t)0xffff); */
/* //disable SPI interrupts */
/* for(uint8_t i=0; i < it_num_lines; i++) { */
/* pl390_gic_cpuif_SPI_ICDICER_wr(&gic, i, (uint32_t)0xffffffff); */
/* } */
}
uint32_t platform_get_active_irq(void)
{
return pl390_gic_cpuif_ICCIAR_rd(&gic);
}
uint32_t gic_cpu_count(void){
return 1;
/*
* LH: The CPU count can be determined using the gic distributor, but
* it is called before the distributor is initialized. However,
* with the new coreboot it seems to be unnecessary anyway.
*
* return pl390_gic_dist_ICDICTR_cpu_number_rdf(&gic_dist);
*/
}
void gic_raise_softirq(uint8_t cpumask, uint8_t irq)
{
assert(!"NYI"); // This needs distributor access
}
void platform_acknowledge_irq(uint32_t irq)
{
pl390_gic_cpuif_ICCEOIR_rawwr(&gic, irq);
}
//enable interrupt forwarding to processor
void gic_cpu_interface_enable(void)
{
pl390_gic_cpuif_ICCICR_wr(&gic, 0x1);
}
errval_t platform_init_ic_bsp(void) {
gic_init();
gic_cpu_interface_enable();
return SYS_ERR_OK;
}
errval_t platform_init_ic_app(void) {
gic_init();
gic_cpu_interface_enable();
return SYS_ERR_OK;
}
/**
* \brief Enable an PPI interrupt
*
* \see ARM Generic Interrupt Controller Architecture Specification v1.0
*
* \param int_id
* \param prio Priority of the interrupt (lower is higher). We allow 0..15.
* The number of priority bits is implementation specific, but at least 16
* (using bits [7:4] of the priority field, chapter 3.3)
* \param 0 is level-sensitive, 1 is edge-triggered
* \param 0 is N-to-N, 1 is 1-N
*/
errval_t platform_enable_interrupt(uint32_t int_id, uint16_t prio,
bool edge_triggered, bool one_to_n)
{
// Set Interrupt Set-Enable Register
uint32_t ind = int_id / 32;
uint32_t bit_mask = (1U << (int_id % 32));
MSG("platform_enable_interrupt for id=0x%"PRIx32", "
"bit_mask=0x%"PRIx32", index=0x%"PRIx32"\n",
int_id, bit_mask, ind);
enum IrqType irq_type = get_irq_type(int_id);
// We only allow enableing PPI interrupts.
if(irq_type != IrqType_PPI) {
return SYS_ERR_IRQ_INVALID;
}
// Enable
// 1 Bit per interrupt
uint32_t regval = pl390_gic_dist_ICDISER_rd(&gic_dist, ind);
regval |= bit_mask;
pl390_gic_dist_ICDISER_wr(&gic_dist, ind, regval);
// TODO: cleanup pl390 mackerel file so that we don't need bit magic
// here. -SG, 2012/12/13
// Priority
// 8 Bit per interrupt
// chp 4.3.10
ind = int_id/4;
// XXX: check that priorities work properly, -SG, 2012/12/13
prio = (prio & 0xF)<<4;
switch(int_id % 4) {
case 0:
pl390_gic_dist_ICDIPR_prio_off0_wrf(&gic_dist, ind, prio);
break;
case 1:
pl390_gic_dist_ICDIPR_prio_off1_wrf(&gic_dist, ind, prio);
break;
case 2:
pl390_gic_dist_ICDIPR_prio_off2_wrf(&gic_dist, ind, prio);
break;
case 3:
pl390_gic_dist_ICDIPR_prio_off3_wrf(&gic_dist, ind, prio);
break;
}
// Configuration registers
// 2 Bit per IRQ
ind = int_id/16;
uint8_t val = ((edge_triggered&0x1) << 1) | (one_to_n&0x1);
switch (int_id % 16) {
case 0:
pl390_gic_dist_ICDICR_conf0_wrf(&gic_dist, ind, val);
break;
case 1:
pl390_gic_dist_ICDICR_conf1_wrf(&gic_dist, ind, val);
break;
case 2:
pl390_gic_dist_ICDICR_conf2_wrf(&gic_dist, ind, val);
break;
case 3:
pl390_gic_dist_ICDICR_conf3_wrf(&gic_dist, ind, val);
break;
case 4:
pl390_gic_dist_ICDICR_conf4_wrf(&gic_dist, ind, val);
break;
case 5:
pl390_gic_dist_ICDICR_conf5_wrf(&gic_dist, ind, val);
break;
case 6:
pl390_gic_dist_ICDICR_conf6_wrf(&gic_dist, ind, val);
break;
case 7:
pl390_gic_dist_ICDICR_conf7_wrf(&gic_dist, ind, val);
break;
case 8:
pl390_gic_dist_ICDICR_conf8_wrf(&gic_dist, ind, val);
break;
case 9:
pl390_gic_dist_ICDICR_conf9_wrf(&gic_dist, ind, val);
break;
case 10:
pl390_gic_dist_ICDICR_conf10_wrf(&gic_dist, ind, val);
break;
case 11:
pl390_gic_dist_ICDICR_conf11_wrf(&gic_dist, ind, val);
break;
case 12:
pl390_gic_dist_ICDICR_conf12_wrf(&gic_dist, ind, val);
break;
case 13:
pl390_gic_dist_ICDICR_conf13_wrf(&gic_dist, ind, val);
break;
case 14:
pl390_gic_dist_ICDICR_conf14_wrf(&gic_dist, ind, val);
break;
case 15:
pl390_gic_dist_ICDICR_conf15_wrf(&gic_dist, ind, val);
break;
}
return SYS_ERR_OK;
}