summaryrefslogtreecommitdiff
path: root/ports/cortex_a7/gnu/example_build/MP_GIC.s
blob: 6f093bd7402e4c896c4b67651d3861e57b4df7d8 (plain)
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
//----------------------------------------------------------------
// Copyright (c) 2005-2018 Arm Limited (or its affiliates). All rights reserved.
// Use, modification and redistribution of this file is subject to your possession of a
// valid End User License Agreement for the Arm Product of which these examples are part of
// and your compliance with all applicable terms and conditions of such licence agreement.
//
// Cortex-A7MP example - Startup Code
//----------------------------------------------------------------
    .text

//----------------------------------------------------------------
// GIC. Generic Interrupt Controller Architecture Specification
//----------------------------------------------------------------

    // CPU Interface offset from base of private peripheral space --> 0x0100
    // Interrupt Distributor offset from base of private peripheral space --> 0x1000

    // Typical calls to enable interrupt ID X:
    // enableIntID(X)                    <-- Enable that ID
    // setIntPriority(X, 0)              <-- Set the priority of X to 0 (the max priority)
    // setPriorityMask(0x1F)             <-- Set CPU's priority mask to 0x1F (the lowest priority)
    // enableGIC()                       <-- Enable the GIC (global)
    // enableGICProcessorInterface()     <-- Enable the CPU interface (local to the CPU)


    // void enableGIC(void)
    // Global enable of the Interrupt Distributor
    .global enableGIC
    .type   enableGIC,function
enableGIC:
    // Get base address of private peripheral space
    MRC     p15, 4, r0, c15, c0, 0     // Read periph base address
    ADD     r0, r0, #0x1000            // Add the GIC offset

    LDR     r1, [r0]                   // Read the GIC Enable Register  (ICDDCR)
    ORR     r1, r1, #0x01              // Set bit 0, the enable bit
    STR     r1, [r0]                   // Write the GIC Enable Register  (ICDDCR)

    BX      lr

// ------------------------------------------------------------

    .global disableGIC
    .type   disableGIC,function
    // void disableGIC(void)
    // Global disable of the Interrupt Distributor
disableGIC:
    // Get base address of private peripheral space
    MRC     p15, 4, r0, c15, c0, 0     // Read periph base address
    ADD     r0, r0, #0x1000            // Add the GIC offset

    LDR     r1, [r0]                   // Read the GIC Enable Register  (ICDDCR)
    BIC     r1, r1, #0x01              // Clear bit 0, the enable bit
    STR     r1, [r0]                   // Write the GIC Enable Register  (ICDDCR)

    BX      lr


// ------------------------------------------------------------

    .global enableIntID
    .type   enableIntID,function
    // void enableIntID(unsigned int ID)
    // Enables the interrupt source number ID
enableIntID:
    // Get base address of private peripheral space
    MOV     r1, r0                     // Back up passed in ID value
    MRC     p15, 4, r0, c15, c0, 0     // Read periph base address

    // Each interrupt source has an enable bit in the GIC.  These
    // are grouped into registers, with 32 sources per register
    // First, we need to identify which 32-bit block the interrupt lives in
    MOV     r2, r1                     // Make working copy of ID in r2
    MOV     r2, r2, LSR #5             // LSR by 5 places, affective divide by 32
                                        // r2 now contains the 32-bit block this ID lives in
    MOV     r2, r2, LSL #2             // Now multiply by 4, to convert offset into an address offset (four bytes per reg)

    // Now work out which bit within the 32-bit block the ID is
    AND     r1, r1, #0x1F              // Mask off to give offset within 32-bit block
    MOV     r3, #1                     // Move enable value into r3
    MOV     r3, r3, LSL r1             // Shift it left to position of ID

    ADD     r2, r2, #0x1100            // Add the base offset of the Enable Set registers to the offset for the ID
    STR     r3, [r0, r2]               // Store out  (ICDISER)

    BX      lr


// ------------------------------------------------------------

    .global disableIntID
    .type   disableIntID,function
    // void disableIntID(unsigned int ID)
    // Disables the interrupt source number ID
disableIntID:
    // Get base address of private peripheral space
    MOV     r1, r0                     // Back up passed in ID value
    MRC     p15, 4, r0, c15, c0, 0     // Read periph base address

    // First, we need to identify which 32-bit block the interrupt lives in
    MOV     r2, r1                     // Make working copy of ID in r2
    MOV     r2, r2, LSR #5             // LSR by 5 places, affective divide by 32
                                        // r2 now contains the 32-bit block this ID lives in
    MOV     r2, r2, LSL #2             // Now multiply by 4, to convert offset into an address offset (four bytes per reg)

    // Now work out which bit within the 32-bit block the ID is
    AND     r1, r1, #0x1F              // Mask off to give offset within 32-bit block
    MOV     r3, #1                     // Move enable value into r3
    MOV     r3, r3, LSL r1             // Shift it left to position of ID in 32-bit block

    ADD     r2, r2, #0x1180            // Add the base offset of the Enable Clear registers to the offset for the ID
    STR     r3, [r0, r2]               // Store out (ICDICER)

    BX      lr


// ------------------------------------------------------------

        .global setIntPriority
        .type   setIntPriority,function
        // void setIntPriority(unsigned int ID, unsigned int priority)
        // Sets the priority of the specified ID
        // r0 = ID
        // r1 = priority
setIntPriority:
        // Get base address of private peripheral space
        MOV     r2, r0                     // Back up passed in ID value
        MRC     p15, 4, r0, c15, c0, 0     // Read periph base address

        // r0 = base addr
        // r1 = priority
        // r2 = ID

        // Make sure that priority value is only 5 bits, and convert to expected format
        AND     r1, r1, #0x1F
        MOV     r1, r1, LSL #3

        // Find which register this ID lives in
        BIC     r3, r2, #0x03              // Make a copy of the ID, clearing off the bottom two bits
                                           // There are four IDs per reg, by clearing the bottom two bits we get an address offset
        ADD     r3, r3, #0x1400            // Now add the offset of the Priority Level registers from the base of the private peripheral space
        ADD     r0, r0, r3                 // Now add in the base address of the private peripheral space, giving us the absolute address

        // Now work out which ID in the register it is
        AND     r2, r2, #0x03              // Clear all but the bottom two bits, leaves which ID in the reg it is (which byte)
        MOV     r2, r2, LSL #3             // Multiply by 8, this gives a bit offset

        // Read -> Modify -> Write
        MOV     r12, #0xFF                 // 8 bit field mask
        MOV     r12, r12, LSL r2           // Move mask into correct bit position
        MOV     r1, r1, LSL r2             // Also, move passed in priority value into correct bit position

        LDR     r3, [r0]                   // Read current value of the Priority Level register (ICDIPR)
        BIC     r3, r3, r12                // Clear appropriate field
        ORR     r3, r3, r1                 // Now OR in the priority value
        STR     r3, [r0]                   // And store it back again  (ICDIPR)

        BX      lr


// ------------------------------------------------------------

        .global enableGICProcessorInterface
        .type   enableGICProcessorInterface,function
        // void enableGICProcessorInterface(void)
        // Enables the processor interface
        // Must be done on each core separately
enableGICProcessorInterface:
        MRC     p15, 4, r0, c15, c0, 0     // Read periph base address
        ADD     r0, r0, #0x2000

        LDR     r1, [r0, #0x0]           // Read the Processor Interface Control register   (ICCICR/ICPICR)
        ORR     r1, r1, #0x03              // Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts
        BIC     r1, r1, #0x08              // Bit 3: Ensure Group 0 interrupts are signalled using IRQ, not FIQ
        STR     r1, [r0, #0x0]           // Write the Processor Interface Control register  (ICCICR/ICPICR)

        BX      lr



// ------------------------------------------------------------

        .global disableGICProcessorInterface
        .type   disableGICProcessorInterface,function
        // void disableGICProcessorInterface(void)
        // Disables the processor interface
        // Must be done on each core separately
disableGICProcessorInterface:

        MRC     p15, 4, r0, c15, c0, 0     // Read periph base address
        ADD     r0, r0, #0x2000

        LDR     r1, [r0, #0x0]           // Read the Processor Interface Control register   (ICCICR/ICPICR)
        BIC     r1, r1, #0x03              // Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts
        STR     r1, [r0, #0x0]           // Write the Processor Interface Control register  (ICCICR/ICPICR)

        BX      lr



// ------------------------------------------------------------

        .global setPriorityMask
        .type   setPriorityMask,function
        // void setPriorityMask(unsigned int priority)
        // Sets the Priority mask register for the CPU run on
        // The reset value masks ALL interrupts!
setPriorityMask:

        // Get base address of private peripheral space
        MRC     p15, 4, r1, c15, c0, 0     // Read periph base address
        ADD     r1, r1, #0x2000

        STR     r0, [r1, #0x4]          // Write the Priority Mask register (ICCPMR/ICCIPMR)

        BX      lr


// ------------------------------------------------------------

        .global setBinaryPoint
        .type   setBinaryPoint,function
       // void setBinaryPoint(unsigned int priority)
       // Sets the Binary Point Register for the CPU run on
setBinaryPoint:

       // Get base address of private peripheral space
       MRC     p15, 4, r1, c15, c0, 0  // Read periph base address
       ADD     r1, r1, #0x2000

       STR     r0, [r1, #0x8]       // Write the Binary register   (ICCBPR/ICCBPR)

       BX      lr


// ------------------------------------------------------------

        .global readIntAck
        .type   readIntAck,function
       // unsigned int readIntAck(void)
       // Returns the value of the Interrupt Acknowledge Register
readIntAck:
       MRC     p15, 4, r0, c15, c0, 0      // Read periph base address
       ADD     r0, r0, #0x2000

       LDR     r0, [r0, #0xC]           // Read the Interrupt Acknowledge Register  (ICCIAR)
       BX      lr


// ------------------------------------------------------------

        .global writeEOI
        .type   writeEOI,function
       // void writeEOI(unsigned int ID)
       // Writes ID to the End Of Interrupt register
writeEOI:

       // Get base address of private peripheral space
       MRC     p15, 4, r1, c15, c0, 0      // Read periph base address
       ADD     r1, r1, #0x2000

       STR     r0, [r1, #0x10]           // Write ID to the End of Interrupt register (ICCEOIR)

       BX      lr


//----------------------------------------------------------------
// SGI
//----------------------------------------------------------------

        .global sendSGI
        .type   sendSGI,function
       // void sendSGI(unsigned int ID, unsigned int target_list, unsigned int filter_list)//
       // Send a software generate interrupt
sendSGI:
       AND     r3, r0, #0x0F               // Mask off unused bits of ID, and move to r3
       AND     r1, r1, #0x0F               // Mask off unused bits of target_filter
       AND     r2, r2, #0x0F               // Mask off unused bits of filter_list

       ORR     r3, r3, r1, LSL #16         // Combine ID and target_filter
       ORR     r3, r3, r2, LSL #24         // and now the filter list

       // Get the address of the GIC
       MRC     p15, 4, r0, c15, c0, 0      // Read periph base address
       ADD     r0, r0, #0x1F00             // Add offset of the sgi_trigger reg

       STR     r3, [r0]                    // Write to the Software Generated Interrupt Register  (ICDSGIR)

       BX      lr


//----------------------------------------------------------------
// End of MP_GIC.s
//----------------------------------------------------------------