Initial upstream commit

The history contained unlicensed code so everything got squashed, sorry.

Change-Id: I9f5775208f9df6fb29074bf3bc498f68cb17b3a0
Signed-off-by: Nico Huber <nico.huber@secunet.com>
diff --git a/common/haswell_shared/hw-gfx-gma-power_and_clocks_haswell.adb b/common/haswell_shared/hw-gfx-gma-power_and_clocks_haswell.adb
new file mode 100644
index 0000000..b46c29d
--- /dev/null
+++ b/common/haswell_shared/hw-gfx-gma-power_and_clocks_haswell.adb
@@ -0,0 +1,235 @@
+--
+-- Copyright (C) 2014-2016 secunet Security Networks AG
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+
+with GNAT.Source_Info;
+
+with HW.Time;
+with HW.Debug;
+with HW.GFX.GMA.Config;
+with HW.GFX.GMA.Registers;
+
+package body HW.GFX.GMA.Power_And_Clocks_Haswell is
+
+   PWR_WELL_CTL_ENABLE_REQUEST   : constant := 1 * 2 ** 31;
+   PWR_WELL_CTL_DISABLE_REQUEST  : constant := 0 * 2 ** 31;
+   PWR_WELL_CTL_STATE_ENABLED    : constant := 1 * 2 ** 30;
+
+   ----------------------------------------------------------------------------
+
+   SRD_CTL_ENABLE          : constant := 1 * 2 ** 31;
+   SRD_STATUS_STATE_MASK   : constant := 7 * 2 ** 29;
+
+   type Pipe is (EDP, A, B, C);
+   type SRD_Regs is record
+      CTL     : Registers.Registers_Index;
+      STATUS  : Registers.Registers_Index;
+   end record;
+   type SRD_Per_Pipe_Regs is array (Pipe) of SRD_Regs;
+   SRD : constant SRD_Per_Pipe_Regs := SRD_Per_Pipe_Regs'
+     (A     => SRD_Regs'
+        (CTL      => Registers.SRD_CTL_A,
+         STATUS   => Registers.SRD_STATUS_A),
+      B     => SRD_Regs'
+        (CTL      => Registers.SRD_CTL_B,
+         STATUS   => Registers.SRD_STATUS_B),
+      C     => SRD_Regs'
+        (CTL      => Registers.SRD_CTL_C,
+         STATUS   => Registers.SRD_STATUS_C),
+      EDP   => SRD_Regs'
+        (CTL      => Registers.SRD_CTL_EDP,
+         STATUS   => Registers.SRD_STATUS_EDP));
+
+   ----------------------------------------------------------------------------
+
+   IPS_CTL_ENABLE          : constant := 1 * 2 ** 31;
+   DISPLAY_IPS_CONTROL     : constant := 16#19#;
+
+   GT_MAILBOX_READY        : constant := 1 * 2 ** 31;
+
+   ----------------------------------------------------------------------------
+
+   procedure PSR_Off
+   is
+      Enabled : Boolean;
+   begin
+      pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+      if Config.Has_Per_Pipe_SRD then
+         for P in Pipe loop
+            Registers.Is_Set_Mask (SRD (P).CTL, SRD_CTL_ENABLE, Enabled);
+            if Enabled then
+               Registers.Unset_Mask (SRD (P).CTL, SRD_CTL_ENABLE);
+               Registers.Wait_Unset_Mask (SRD (P).STATUS, SRD_STATUS_STATE_MASK);
+
+               pragma Debug (Debug.Put_Line ("Disabled PSR."));
+            end if;
+         end loop;
+      else
+         Registers.Is_Set_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE, Enabled);
+         if Enabled then
+            Registers.Unset_Mask (Registers.SRD_CTL, SRD_CTL_ENABLE);
+            Registers.Wait_Unset_Mask (Registers.SRD_STATUS, SRD_STATUS_STATE_MASK);
+
+            pragma Debug (Debug.Put_Line ("Disabled PSR."));
+         end if;
+      end if;
+   end PSR_Off;
+
+   ----------------------------------------------------------------------------
+
+   procedure GT_Mailbox_Write (MBox : Word32; Value : Word32) is
+   begin
+      pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+      Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
+      Registers.Write (Registers.GT_MAILBOX_DATA, Value);
+      Registers.Write (Registers.GT_MAILBOX, GT_MAILBOX_READY or MBox);
+
+      Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
+      Registers.Write (Registers.GT_MAILBOX_DATA, 0);
+   end GT_Mailbox_Write;
+
+   procedure IPS_Off
+   is
+      Enabled : Boolean;
+   begin
+      pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+      if Config.Has_IPS then
+         Registers.Is_Set_Mask (Registers.IPS_CTL, IPS_CTL_ENABLE, Enabled);
+         if Enabled then
+            if Config.Has_IPS_CTL_Mailbox then
+               GT_Mailbox_Write (DISPLAY_IPS_CONTROL, 0);
+               -- May take up to 42ms.
+               Registers.Wait_Unset_Mask (Registers.IPS_CTL, IPS_CTL_ENABLE);
+            else
+               Registers.Unset_Mask (Registers.IPS_CTL, IPS_CTL_ENABLE);
+            end if;
+
+            pragma Debug (Debug.Put_Line ("Disabled IPS."));
+            -- We have to wait until the next vblank here.
+            -- 20ms should be enough.
+            Time.M_Delay (20);
+         end if;
+      end if;
+   end IPS_Off;
+
+   ----------------------------------------------------------------------------
+
+   procedure PDW_Off
+   is
+      Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
+   begin
+      pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+      Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
+      Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
+      Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
+      Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
+      pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); --  Result for debugging only
+      pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); --  Result for debugging only
+
+      if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
+          PWR_WELL_CTL_ENABLE_REQUEST) /= 0
+      then
+         Registers.Wait_Set_Mask
+           (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_STATE_ENABLED);
+      end if;
+
+      if (Ctl1 and PWR_WELL_CTL_ENABLE_REQUEST) /= 0 then
+         Registers.Write (Registers.PWR_WELL_CTL_BIOS, PWR_WELL_CTL_DISABLE_REQUEST);
+      end if;
+
+      if (Ctl2 and PWR_WELL_CTL_ENABLE_REQUEST) /= 0 then
+         Registers.Write (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_DISABLE_REQUEST);
+      end if;
+   end PDW_Off;
+
+   procedure PDW_On
+   is
+      Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
+   begin
+      pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
+
+      Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
+      Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
+      Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
+      Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
+      pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); --  Result for debugging only
+      pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); --  Result for debugging only
+
+      if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
+          PWR_WELL_CTL_ENABLE_REQUEST) = 0
+      then
+         Registers.Wait_Unset_Mask
+           (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_STATE_ENABLED);
+      end if;
+
+      if (Ctl2 and PWR_WELL_CTL_ENABLE_REQUEST) = 0 then
+         Registers.Write (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_ENABLE_REQUEST);
+         Registers.Wait_Set_Mask
+           (Registers.PWR_WELL_CTL_DRIVER, PWR_WELL_CTL_STATE_ENABLED);
+      end if;
+   end PDW_On;
+
+   function Need_PDW (Checked_Configs : Configs_Type) return Boolean is
+   begin
+      return (Checked_Configs (Primary).Port /= Disabled and
+              Checked_Configs (Primary).Port /= Internal) or
+             Checked_Configs (Secondary).Port /= Disabled or
+             Checked_Configs (Tertiary).Port /= Disabled;
+   end Need_PDW;
+
+   ----------------------------------------------------------------------------
+
+   procedure Pre_All_Off is
+   begin
+      -- HSW: disable panel self refresh (PSR) on eDP if enabled
+         -- wait for PSR idling
+      PSR_Off;
+      IPS_Off;
+   end Pre_All_Off;
+
+   procedure Initialize is
+   begin
+      -- HSW: disable power down well
+      PDW_Off;
+   end Initialize;
+
+   procedure Power_Set_To (Configs : Configs_Type) is
+   begin
+      if Need_PDW (Configs) then
+         PDW_On;
+      else
+         PDW_Off;
+      end if;
+   end Power_Set_To;
+
+   procedure Power_Up (Old_Configs, New_Configs : Configs_Type) is
+   begin
+      if not Need_PDW (Old_Configs) and Need_PDW (New_Configs) then
+         PDW_On;
+      end if;
+   end Power_Up;
+
+   procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Configs_Type)
+   is
+   begin
+      if (Need_PDW (Old_Configs) or Need_PDW (Tmp_Configs)) and
+         not Need_PDW (New_Configs)
+      then
+         PDW_Off;
+      end if;
+   end Power_Down;
+
+end HW.GFX.GMA.Power_And_Clocks_Haswell;