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 14 enum 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 */ 40 volatile 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 getActiveIRQ(void)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 */ isIRQPending(void)84static inline bool_t isIRQPending(void) 85 { 86 return getActiveIRQ() != irqInvalid; 87 } 88 89 /* Enable or disable irq according to the 'disable' flag. */ maskInterrupt(bool_t disable,irq_t irq)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 ackInterrupt(irq_t irq)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 handleSpuriousIRQ(void)114static inline void handleSpuriousIRQ(void) 115 { 116 /* Reset and re-enable IRQs. */ 117 intc->intcps_control = INTCPS_CONTROL_NEWIRQAGR; 118 dsb(); 119 } 120 121