File : s-bbbosu-ppc-openpic.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . B B . B O A R D _ S U P P O R T --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1999-2002 Universidad Politecnica de Madrid --
10 -- Copyright (C) 2003-2005 The European Space Agency --
11 -- Copyright (C) 2003-2016, AdaCore --
12 -- --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 3, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. --
19 -- --
20 -- --
21 -- --
22 -- --
23 -- --
24 -- You should have received a copy of the GNU General Public License and --
25 -- a copy of the GCC Runtime Library Exception along with this program; --
26 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
27 -- <http://www.gnu.org/licenses/>. --
28 -- --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
31 -- --
32 -- The port of GNARL to bare board targets was initially developed by the --
33 -- Real-Time Systems Group at the Technical University of Madrid. --
34 -- --
35 ------------------------------------------------------------------------------
36
37 with System.BB.Board_Parameters;
38 with System.BB.Parameters;
39 with System.Machine_Code;
40
41 pragma Warnings (off);
42 -- Vectors and priorities are defined in Ada.Interrupts.Names, which is not
43 -- preelaborated. Ignore this issue as we only reference static consants.
44
45 with Ada.Interrupts; use Ada.Interrupts;
46 with Ada.Interrupts.Names; use Ada.Interrupts.Names;
47
48 pragma Warnings (on);
49
50 with Interfaces; use Interfaces;
51
52 package body System.BB.Board_Support is
53
54 type Unsigned_4 is mod 2 ** 4;
55 for Unsigned_4'Size use 4;
56 type Unsigned_1 is mod 2 ** 1;
57 for Unsigned_1'Size use 1;
58
59 type Vector_Priority_Register is record
60 Vector : Unsigned_16;
61 Priority : Unsigned_4;
62 Activity : Unsigned_1;
63 Mask : Unsigned_1;
64 end record with Size => 32;
65
66 for Vector_Priority_Register'Bit_Order use Low_Order_First;
67 for Vector_Priority_Register use record
68 Vector at 0 range 0 .. 15;
69 Priority at 0 range 16 .. 19;
70 Activity at 0 range 30 .. 30;
71 Mask at 0 range 31 .. 31;
72 end record;
73
74 procedure Set_Vpr
75 (Offset : Address;
76 Interrupt : Ada.Interrupts.Interrupt_ID;
77 Priority : Interrupt_Priority);
78 -- Set a VPR register of the OpenPIC at address Offset. Enable interrupt
79
80 function Get_Vpr (Offset : Address) return Vector_Priority_Register;
81 -- Return a VPR register of the OpenPIC at address Offset
82
83 function Vpr_Offset
84 (Interrupt : Ada.Interrupts.Interrupt_ID) return Address;
85 -- Return offset of the vector priority for the given interrupt
86
87 -------------
88 -- Set_Vpr --
89 -------------
90
91 procedure Set_Vpr
92 (Offset : Address;
93 Interrupt : Ada.Interrupts.Interrupt_ID;
94 Priority : Interrupt_Priority)
95 is
96 Vpr : Vector_Priority_Register;
97 for Vpr'Address use System.BB.Board_Parameters.CCSRBAR + Offset;
98 pragma Volatile (Vpr);
99 pragma Import (Ada, Vpr);
100 begin
101 -- We store the interrupt Id in Vpr.Vector, IACK will be set with this
102 -- value when the interrupt is trigger. This allows us to get the ID of
103 -- the triggered interrupt.
104
105 Vpr := (Vector => Unsigned_16 (Interrupt),
106 Priority => Unsigned_4 (Priority - Interrupt_Priority'First),
107 Activity => 0,
108 Mask => 0);
109 end Set_Vpr;
110
111 -------------
112 -- Get_Vpr --
113 -------------
114
115 function Get_Vpr (Offset : Address) return Vector_Priority_Register is
116 Vpr : Vector_Priority_Register;
117 for Vpr'Address use System.BB.Board_Parameters.CCSRBAR + Offset;
118 pragma Volatile (Vpr);
119 pragma Import (Ada, Vpr);
120
121 begin
122 return Vpr;
123 end Get_Vpr;
124
125 ----------------
126 -- Vpr_Offset --
127 ----------------
128
129 function Vpr_Offset
130 (Interrupt : Ada.Interrupts.Interrupt_ID) return Address
131 is
132 Base : Address;
133 Step : Address;
134 Index : Natural;
135 begin
136
137 -- Step between 2 Vpr registers
138 if Interrupt in IPI_Interrupt_ID then
139 Step := 16#10#;
140 else
141 Step := 16#20#;
142 end if;
143
144 case Interrupt is
145 when IPI_Interrupt_ID =>
146 Base := 16#4_10A0#;
147 Index := Natural (Interrupt - IPI_Interrupt_ID'First);
148
149 when External_Interrupt_ID =>
150 Base := 16#5_0000#;
151 Index := Natural (Interrupt - External_Interrupt_ID'First);
152
153 when Internal_Interrupt_ID =>
154 Base := 16#5_0200#;
155 Index := Natural (Interrupt - Internal_Interrupt_ID'First);
156
157 when Messaging_Interrupt_ID => null;
158 Base := 16#5_1600#;
159 Index := Natural (Interrupt - Messaging_Interrupt_ID'First);
160
161 when Shared_Message_Interrupt_ID => null;
162 Base := 16#5_1C00#;
163 Index := Natural (Interrupt - Shared_Message_Interrupt_ID'First);
164
165 when others =>
166 raise Program_Error;
167 end case;
168
169 return Base + Step * Address (Index);
170 end Vpr_Offset;
171
172 ----------------------
173 -- Initialize_Board --
174 ----------------------
175
176 procedure Initialize_Board is
177 begin
178 -- Initialize the OpenPIC
179
180 declare
181 Svr : Unsigned_32;
182 for Svr'Address use
183 System.BB.Board_Parameters.CCSRBAR + 16#4_10E0#;
184 pragma Volatile (Svr);
185 pragma Import (Ada, Svr);
186
187 begin
188 -- Set the spurious vector register as No_Interrupt (0), so that
189 -- spurious interrupts can be easily discarded.
190
191 Svr := 16#0000#;
192 end;
193
194 -- Enable IPI
195
196 Set_Vpr
197 (16#4_10A0#,
198 Ada.Interrupts.Names.Interprocessor_Interrupt_0,
199 Ada.Interrupts.Names.Interprocessor_Interrupt_0_Priority);
200 Set_Vpr
201 (16#4_10B0#,
202 Ada.Interrupts.Names.Interprocessor_Interrupt_1,
203 Ada.Interrupts.Names.Interprocessor_Interrupt_1_Priority);
204 Set_Vpr
205 (16#4_10C0#,
206 Ada.Interrupts.Names.Interprocessor_Interrupt_2,
207 Ada.Interrupts.Names.Interprocessor_Interrupt_2_Priority);
208 Set_Vpr
209 (16#4_10D0#,
210 Ada.Interrupts.Names.Interprocessor_Interrupt_3,
211 Ada.Interrupts.Names.Interprocessor_Interrupt_3_Priority);
212
213 -- Mask interrupts
214
215 Set_Current_Priority (Interrupt_Priority'Last - 1);
216 end Initialize_Board;
217
218 ---------------------------
219 -- Clear_Alarm_Interrupt --
220 ---------------------------
221
222 procedure Clear_Alarm_Interrupt is
223 use System.Machine_Code;
224
225 begin
226 if System.BB.CPU_Specific.PowerPC_Book_E then
227 -- Clear TSR[DIS] on Book-E CPUs (e500)
228
229 Asm ("mtspr 336,%0",
230 Inputs => Unsigned_32'Asm_Input ("r", 2 ** (63 - 36)),
231 Volatile => True);
232 end if;
233 end Clear_Alarm_Interrupt;
234
235 ---------------------------
236 -- Get_Interrupt_Request --
237 ---------------------------
238
239 function Get_Interrupt_Request
240 (Vector : CPU_Specific.Vector_Id)
241 return System.BB.Interrupts.Interrupt_ID
242 is
243 pragma Unreferenced (Vector);
244
245 Iack : Unsigned_32;
246 for Iack'Address use
247 System.BB.Board_Parameters.CCSRBAR + 16#4_00A0#;
248 pragma Volatile (Iack);
249 pragma Import (Ada, Iack);
250 -- Interrupt acknowledge register
251
252 begin
253 return System.BB.Interrupts.Interrupt_ID (Iack);
254 end Get_Interrupt_Request;
255
256 -------------------------------
257 -- Install_Interrupt_Handler --
258 -------------------------------
259
260 procedure Install_Interrupt_Handler
261 (Handler : Address;
262 Interrupt : Interrupts.Interrupt_ID;
263 Prio : Interrupt_Priority)
264 is
265 Offset : constant Address :=
266 Vpr_Offset (Ada.Interrupts.Interrupt_ID (Interrupt));
267 begin
268 CPU_Specific.Install_Exception_Handler
269 (Handler, CPU_Specific.External_Interrupt_Excp);
270 Set_Vpr (Offset, Ada.Interrupts.Interrupt_ID (Interrupt), Prio);
271 end Install_Interrupt_Handler;
272
273 ---------------------------
274 -- Priority_Of_Interrupt --
275 ---------------------------
276
277 function Priority_Of_Interrupt
278 (Interrupt : System.BB.Interrupts.Interrupt_ID) return System.Any_Priority
279 is
280 Vpr : constant Vector_Priority_Register :=
281 Get_Vpr (Vpr_Offset (Ada.Interrupts.Interrupt_ID (Interrupt)));
282 begin
283 return System.Interrupt_Priority'First +
284 System.Any_Priority (Vpr.Priority);
285 end Priority_Of_Interrupt;
286
287 ----------------
288 -- Power_Down --
289 ----------------
290
291 procedure Power_Down is
292 use System.Machine_Code;
293 POW : constant Unsigned_32 := 2 ** 18;
294 Msr : Unsigned_32;
295 begin
296 -- See sequences on:
297 --
298 -- PowerPc e500 Core Familiy Reference Manual
299 -- Section 6.4.1 Software Considerations for Power Management
300
301 if System.BB.CPU_Specific.PowerPC_Book_E then
302
303 -- Read MSR and set POW/WE bit
304
305 Asm ("mfmsr %0",
306 Outputs => Unsigned_32'Asm_Output ("=r", Msr),
307 Volatile => True);
308 Msr := Msr or POW;
309
310 Asm ("msync", Volatile => True);
311
312 -- Set MSR
313
314 Asm ("mtmsr %0",
315 Inputs => Unsigned_32'Asm_Input ("r", Msr),
316 Volatile => True);
317
318 Asm ("isync", Volatile => True);
319 end if;
320 end Power_Down;
321
322 -----------------------------
323 -- Clear_Interrupt_Request --
324 -----------------------------
325
326 procedure Clear_Interrupt_Request
327 (Interrupt : System.BB.Interrupts.Interrupt_ID)
328 is
329 pragma Unreferenced (Interrupt);
330 EOI : Unsigned_32;
331 for EOI'Address use System.BB.Board_Parameters.CCSRBAR + 16#4_00B0#;
332 pragma Volatile (EOI);
333 pragma Import (Ada, EOI);
334 begin
335 EOI := 0;
336 end Clear_Interrupt_Request;
337
338 --------------------------
339 -- Set_Current_Priority --
340 --------------------------
341
342 procedure Set_Current_Priority (Priority : Integer) is
343 CTPR : Unsigned_32;
344 for CTPR'Address use System.BB.Board_Parameters.CCSRBAR + 16#4_0080#;
345 pragma Volatile (CTPR);
346 pragma Import (Ada, CTPR);
347
348 begin
349 -- Note that Priority cannot be the last one, as this procedure is
350 -- unable to disable the decrementer interrupt.
351
352 pragma Assert (Priority /= Interrupt_Priority'Last);
353
354 if Priority in Interrupt_Priority then
355 CTPR := Unsigned_32 (Priority - Interrupt_Priority'First);
356 else
357 CTPR := 0;
358 end if;
359 end Set_Current_Priority;
360
361 end System.BB.Board_Support;