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;