1284990Scy/* 2284990Scy * Copyright 2019, Data61 3284990Scy * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4284990Scy * ABN 41 687 119 230. 5284990Scy * 6284990Scy * This software may be distributed and modified according to the terms of 7284990Scy * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8284990Scy * See "LICENSE_BSD2.txt" for details. 9284990Scy * 10284990Scy * @TAG(DATA61_BSD) 11284990Scy */ 12284990Scy 13284990Scy#include <assert.h> 14284990Scy#include <stdbool.h> 15284990Scy 16284990Scy#include <utils/util.h> 17284990Scy 18284990Scy#include "../../../irqchip.h" 19284990Scy 20284990Scy#define ARM_GIC_INT_CELL_COUNT 3 21284990Scy 22284990Scy#define SPI_IRQ_TYPE 0 23284990Scy#define PPI_IRQ_TYPE 1 24284990Scy 25289997Sglebius/* These offsets are in the context of the normal 'interrupts' property, 26289997Sglebius * for the 'interrupts-extended' property, we add one to each */ 27293650Sglebiustypedef enum { 28284990Scy INT_TYPE_OFFSET, 29284990Scy INT_OFFSET 30284990Scy} interrupt_cell_offset; 31284990Scy 32284990Scytypedef enum { 33284990Scy EXT_INT_CONTROLLER_OFFSET, 34284990Scy EXT_INT_TYPE_OFFSET, 35284990Scy EXT_INT_OFFSET 36289997Sglebius} ext_interrupt_cell_offset; 37289997Sglebius 38284990Scy/* Note for extended interrupts, we expect the common case that the interrupt controller phandles 39284990Scy * for each block in the property is the same as the GICs phandle */ 40284990Scystatic int parse_arm_gic_interrupts(char *dtb_blob, int node_offset, int intr_controller_phandle, 41284990Scy irq_walk_cb_fn_t callback, void *token) 42284990Scy{ 43289997Sglebius bool is_extended = false; 44284990Scy int prop_len = 0; 45289997Sglebius const void *interrupts_prop = get_interrupts_prop(dtb_blob, node_offset, &is_extended, &prop_len); 46284990Scy assert(interrupts_prop != NULL); 47289997Sglebius int total_cells = prop_len / sizeof(uint32_t); 48284990Scy 49289997Sglebius int stride = ARM_GIC_INT_CELL_COUNT + (is_extended == true); 50289997Sglebius int num_interrupts = total_cells / stride; 51293650Sglebius 52284990Scy assert(total_cells % stride == 0); 53284990Scy 54284990Scy for (int i = 0; i < num_interrupts; i++) { 55 ps_irq_t curr_irq = {0}; 56 const void *curr = interrupts_prop + (i * stride * sizeof(uint32_t)); 57 curr_irq.type = PS_INTERRUPT; 58 uint32_t irq_type = 0; 59 uint32_t irq = 0; 60 if (is_extended) { 61 if (READ_CELL(1, curr, EXT_INT_CONTROLLER_OFFSET) != intr_controller_phandle) { 62 /* Bail, we hit the uncommon case where this device has interrupts routed to 63 * different interrupt controllers */ 64 return -EINVAL; 65 } 66 irq_type = READ_CELL(1, curr, EXT_INT_TYPE_OFFSET); 67 irq = READ_CELL(1, curr, EXT_INT_OFFSET); 68 } else { 69 irq_type = READ_CELL(1, curr, INT_TYPE_OFFSET); 70 irq = READ_CELL(1, curr, INT_OFFSET); 71 } 72 curr_irq.irq.number = irq + (irq_type == SPI_IRQ_TYPE ? 32 : 0); 73 int error = callback(curr_irq, i, num_interrupts, token); 74 if (error) { 75 return error; 76 } 77 } 78 79 return 0; 80} 81 82char *arm_gic_compatible_list[] = { 83 "arm,gic-400", 84 "arm,cortex-a9-gic", 85 "arm,cortex-a15-gic", 86 NULL 87}; 88DEFINE_IRQCHIP_PARSER(arm_gic, arm_gic_compatible_list, parse_arm_gic_interrupts); 89