1 /*
2  * Copyright 2014, General Dynamics C4 Systems
3  *
4  * SPDX-License-Identifier: GPL-2.0-only
5  */
6 
7 #include <linker.h>
8 #include <machine/io.h>
9 #include <plat/machine/hardware.h>
10 #include <plat/machine/pic.h>
11 
12 /* PIC (i8259) base registers */
13 #define PIC1_BASE 0x20
14 #define PIC2_BASE 0xa0
15 
16 /* Program PIC (i8259) to remap IRQs 0-15 to interrupt vectors starting at 'interrupt' */
pic_remap_irqs(interrupt_t interrupt)17 BOOT_CODE void pic_remap_irqs(interrupt_t interrupt)
18 {
19     out8(PIC1_BASE, 0x11);
20     out8(PIC2_BASE, 0x11);
21     out8(PIC1_BASE + 1, interrupt);
22     out8(PIC2_BASE + 1, interrupt + 8);
23     out8(PIC1_BASE + 1, 0x04);
24     out8(PIC2_BASE + 1, 0x02);
25     out8(PIC1_BASE + 1, 0x01);
26     out8(PIC2_BASE + 1, 0x01);
27     out8(PIC1_BASE + 1, 0x0);
28     out8(PIC2_BASE + 1, 0x0);
29 }
30 
pic_disable(void)31 BOOT_CODE void pic_disable(void)
32 {
33     /* We assume that pic_remap_irqs has already been called and
34      * just mask all the irqs */
35     out8(PIC1_BASE + 1, 0xff);
36     out8(PIC2_BASE + 1, 0xff);
37 }
38 
pic_mask_irq(bool_t mask,irq_t irq)39 void pic_mask_irq(bool_t mask, irq_t irq)
40 {
41     uint8_t  bit_mask;
42     uint16_t pic_port;
43 
44     assert(irq >= irq_isa_min);
45     assert(irq <= irq_isa_max);
46 
47     if (irq < 8) {
48         bit_mask = BIT(irq);
49         pic_port = PIC1_BASE + 1;
50     } else {
51         bit_mask = BIT(irq - 8);
52         pic_port = PIC2_BASE + 1;
53     }
54 
55     if (mask) {
56         /* Disables the interrupt */
57         out8(pic_port, (in8(pic_port) | bit_mask));
58     } else {
59         /* Enables the interrupt */
60         out8(pic_port, (in8(pic_port) & ~bit_mask));
61     }
62 }
63 
pic_is_irq_pending(void)64 bool_t pic_is_irq_pending(void)
65 {
66     /* Interrupt Request Register (IRR) - holds pending IRQs */
67     uint8_t irr;
68 
69     /* Send to PIC1's OCW3, in order to read IRR from next inb instruction */
70     out8(PIC1_BASE, 0x0a);
71 
72     /* Read IRR */
73     irr = in8(PIC1_BASE);
74 
75     /* Since slave PIC is connected to IRQ2 of master PIC,
76      * there is no need to check IRR of slave PIC.
77      */
78     return irr != 0;
79 }
80 
pic_get_isr(void)81 static uint16_t pic_get_isr(void)
82 {
83     out8(PIC1_BASE, 0x0b);
84     out8(PIC2_BASE, 0x0b);
85     return (((uint16_t)in8(PIC2_BASE)) << 8) | in8(PIC1_BASE);
86 }
87 
pic_ack_active_irq(void)88 void pic_ack_active_irq(void)
89 {
90     irq_t irq = getActiveIRQ();
91     if (irq >= irq_isa_min + 8) {
92         /* ack slave PIC, unless we got a spurious irq 15
93          * It is spurious if the bit is not set in the ISR
94          * Even if it was spurious we will still need to
95          * acknowledge the master PIC */
96         if (irq != irq_isa_min + 15 || (pic_get_isr() & BIT(15))) {
97             out8(PIC2_BASE, 0x20);
98         }
99     }
100     /* ack master PIC, unless we got a spurious IRQ 7
101      * It is spurious if the bit is not set in the ISR */
102     if (irq != irq_isa_min + 7 || (pic_get_isr() & BIT(7))) {
103         out8(PIC1_BASE, 0x20);
104     }
105 }
106