blob: cc59aae857f99e8c7b62a6cca1ce45c12d0aeb2b (
plain) (
blame)
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
/* opbintctrl.c
*
* This file contains definitions and declarations for the
* Xilinx Off Processor Bus (OPB) Interrupt Controller
*
* Author: Keith Robertson <kjrobert@alumni.uwaterloo.ca>
* COPYRIGHT (c) 2005 Linn Products Ltd, Scotland.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <bsp/opbintctrl.h>
#include <rtems.h>
#include <rtems/bspIo.h>
#include <bsp/irq.h>
#include <rtems/powerpc/powerpc.h>
/*
* Acknowledge a mask of interrupts.
*/
RTEMS_INLINE_ROUTINE void set_iar(uint32_t mask)
{
*((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_IAR)) = mask;
}
/*
* Set IER state. Used to (dis)enable a mask of vectors.
* If you only have to do one, use enable/disable_vector.
*/
RTEMS_INLINE_ROUTINE void set_ier(uint32_t mask)
{
*((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_IER)) = mask;
}
/*
* Retrieve contents of Interrupt Pending Register
*/
RTEMS_INLINE_ROUTINE uint32_t get_ipr(void)
{
uint32_t c = *((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_IPR));
return c;
}
void BSP_irq_enable_at_opbintc (rtems_irq_number irqnum)
{
*((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_SIE))
= 1 << (irqnum - BSP_OPBINTC_IRQ_LOWEST_OFFSET);
}
void BSP_irq_disable_at_opbintc (rtems_irq_number irqnum)
{
*((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_CIE))
= 1 << (irqnum - BSP_OPBINTC_IRQ_LOWEST_OFFSET);
}
/*
* IRQ Handler: this is called from the primary exception dispatcher
*/
void BSP_irq_handle_at_opbintc(void)
{
uint32_t ipr, iprcopy, mask, i, c;
rtems_irq_connect_data *tbl_entry;
iprcopy = ipr = get_ipr();
c = 0;
mask = 0;
for (i = 0;
(i < BSP_OPBINTC_PER_IRQ_NUMBER)
&& (ipr != 0);
i++) {
c = (1 << i);
if ((ipr & c) != 0) {
/* interrupt is asserted */
mask |= c;
ipr &= ~c;
tbl_entry = &BSP_rtems_irq_tbl[i+BSP_OPBINTC_IRQ_LOWEST_OFFSET];
if (tbl_entry->hdl != NULL) {
(tbl_entry->hdl) (tbl_entry->handle);
} else {
printk("opbintctrl: Spurious interrupt; IPR 0x%08X, vector 0x%x\n\r",
iprcopy, i);
}
}
}
if (mask) {
/* ack all the interrupts we serviced */
set_iar(mask);
}
}
/*
* activate the interrupt controller
*/
rtems_status_code opb_intc_init(void)
{
uint32_t i, mask = 0;
/* mask off all interrupts */
set_ier(0x0);
for (i = 0; i < OPB_INTC_IRQ_MAX; i++) {
mask |= (1 << i);
}
printk("opb_intc_init: mask = 0x%x\n", (unsigned) mask);
/* make sure interupt status register is clear before we enable the interrupt controller */
*((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_ISR)) = 0;
/* acknowledge all interrupt sources */
set_iar(mask);
/* Turn on normal hardware operation of interrupt controller */
*((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_MER)) =
(OPB_INTC_MER_HIE);
/* Enable master interrupt switch for the interrupt controller */
*((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_MER)) =
(OPB_INTC_MER_HIE | OPB_INTC_MER_ME);
return RTEMS_SUCCESSFUL;
}
|