File size: 2,000 Bytes
829b19c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*
 * HAL — Interrupt Controller driver for OMAP3530 AINTC
 */

#include "interrupt.h"

static irq_handler_t irq_handlers[INTC_NUM_IRQS];

void intc_init(void) {
    hw_reg32_t base = (hw_reg32_t)INTC_BASE;

    /* Soft reset */
    reg_write32(base + INTC_SYSCONFIG, 0x02);
    delay_cycles(100);
    while (!(reg_read32(base + INTC_SYSSTATUS) & 0x01))
        ;

    /* Mask all interrupts */
    for (int i = 0; i < INTC_NUM_MIR_REGS; i++) {
        reg_write32(base + INTC_MIR_SET(i), 0xFFFFFFFF);
    }

    /* Clear all handler pointers */
    for (int i = 0; i < INTC_NUM_IRQS; i++) {
        irq_handlers[i] = (irq_handler_t)0;
    }

    /* No priority threshold (all priorities pass) */
    reg_write32(base + INTC_THRESHOLD, 0x00);

    /* Enable protection (only privileged access) */
    reg_write32(base + INTC_PROTECTION, 0x01);
}

void intc_enable_irq(uint8_t irq_num) {
    hw_reg32_t base = (hw_reg32_t)INTC_BASE;
    int bank = irq_num / 32;
    int bit  = irq_num % 32;
    reg_write32(base + INTC_MIR_CLEAR(bank), (1UL << bit));
}

void intc_disable_irq(uint8_t irq_num) {
    hw_reg32_t base = (hw_reg32_t)INTC_BASE;
    int bank = irq_num / 32;
    int bit  = irq_num % 32;
    reg_write32(base + INTC_MIR_SET(bank), (1UL << bit));
}

void intc_set_irq_handler(uint8_t irq_num, irq_handler_t handler) {
    if (irq_num < INTC_NUM_IRQS)
        irq_handlers[irq_num] = handler;
}

uint8_t intc_get_active_irq(void) {
    hw_reg32_t base = (hw_reg32_t)INTC_BASE;
    return (uint8_t)(reg_read32(base + INTC_SIR_IRQ) & 0x7F);
}

void intc_ack_irq(void) {
    hw_reg32_t base = (hw_reg32_t)INTC_BASE;
    reg_write32(base + INTC_CONTROL, 0x01);
}

void intc_enable(void) {
    __asm__ volatile("cpsie i" ::: "memory");
}

void intc_disable(void) {
    __asm__ volatile("cpsid i" ::: "memory");
}

void intc_handle_irq(void) {
    uint8_t irq = intc_get_active_irq();
    if (irq < INTC_NUM_IRQS && irq_handlers[irq]) {
        irq_handlers[irq](irq);
    }
    intc_ack_irq();
}