1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#pragma once 8 9#include <config.h> 10#include <types.h> 11#include <machine/interrupt.h> 12#include <armv/machine.h> 13 14enum irqNumbers { 15 irqInvalid = 255 16}; 17 18#define CMPER_REG(base, off) ((volatile uint32_t *)((base) + (off))) 19#define CMPER_TIMER3_CLKCTRL 0x84 20#define CMPER_TIMER4_CLKCTRL 0x88 21 22#define CMPER_CLKCTRL_DISABLE 0 23#define CMPER_CLKCTRL_ENABLE 2 24 25#define CMPER_CLKSEL_TIMER3 0x50c 26#define CMPER_CLKSEL_TIMER4 0x510 27#define CMPER_CKLSEL_MOSC 1 28 29#define RESERVED 3 30 31#define INTCPS_SYSCONFIG_SOFTRESET BIT(1) 32#define INTCPS_SYSSTATUS_RESETDONE BIT(0) 33#define INTCPS_CONTROL_NEWIRQAGR BIT(0) 34#define INTCPS_SIR_IRQ_SPURIOUSIRQFLAG 0xffffff80 35 36/* 37 * The struct below is used to discourage the compiler from generating literals 38 * for every single address we might access. 39 */ 40volatile struct INTC_map { 41 uint32_t padding[4]; 42 uint32_t intcps_sysconfig; 43 uint32_t intcps_sysstatus; 44 uint32_t padding2[10]; 45 uint32_t intcps_sir_irq; 46 uint32_t intcps_sir_fiq; 47 uint32_t intcps_control; 48 uint32_t intcps_protection; 49 uint32_t intcps_idle; 50 uint32_t padding3[3]; 51 uint32_t intcps_irq_priority; 52 uint32_t intcps_fiq_priority; 53 uint32_t intcps_threshold; 54 uint32_t padding4[5]; 55 struct { 56 uint32_t intcps_itr; 57 uint32_t intcps_mir; 58 uint32_t intcps_mir_clear; 59 uint32_t intcps_mir_set; 60 uint32_t intcps_isr_set; 61 uint32_t intcps_isr_clear; 62 uint32_t intcps_pending_irq; 63 uint32_t intcps_pending_fiq; 64 } intcps_n[4]; 65 uint32_t intcps_ilr[128]; 66} *intc = (volatile void *)INTC_PPTR; 67 68 69static inline irq_t getActiveIRQ(void) 70{ 71 uint32_t intcps_sir_irq = intc->intcps_sir_irq; 72 irq_t irq = (irq_t)(intcps_sir_irq & 0x7f); 73 74 if ((intcps_sir_irq & INTCPS_SIR_IRQ_SPURIOUSIRQFLAG) == 0) { 75 assert((irq / 32) < (sizeof intc->intcps_n / sizeof intc->intcps_n[0])); 76 if (intc->intcps_n[irq / 32].intcps_pending_irq & (1 << (irq & 31))) { 77 return irq; 78 } 79 } 80 return irqInvalid; 81} 82 83/* Check for pending IRQ */ 84static inline bool_t isIRQPending(void) 85{ 86 return getActiveIRQ() != irqInvalid; 87} 88 89/* Enable or disable irq according to the 'disable' flag. */ 90static inline void maskInterrupt(bool_t disable, irq_t irq) 91{ 92 if (likely(irq < maxIRQ)) { 93 if (disable) { 94 intc->intcps_n[irq / 32].intcps_mir_set = 1 << (irq & 31); 95 } else { 96 intc->intcps_n[irq / 32].intcps_mir_clear = 1 << (irq & 31); 97 } 98 } 99} 100 101static inline void ackInterrupt(irq_t irq) 102{ 103 /* 104 * am335x ref man, sec 6.2.2 only requires a DSB after NEWIRQAGR. 105 * I found that without dsb() or more code before, I get interrupts 106 * without the associated pending bit being set. Perhaps this 107 * indicates a missing barrier in code elsewhere? -TimN 108 */ 109 dsb(); 110 intc->intcps_control = INTCPS_CONTROL_NEWIRQAGR; 111 dsb(); 112} 113 114static inline void handleSpuriousIRQ(void) 115{ 116 /* Reset and re-enable IRQs. */ 117 intc->intcps_control = INTCPS_CONTROL_NEWIRQAGR; 118 dsb(); 119} 120 121