diff --git a/common/Makefile.inc b/common/Makefile.inc index fc985b325d..8d6634ea8c 100644 --- a/common/Makefile.inc +++ b/common/Makefile.inc @@ -62,7 +62,9 @@ $(hw-gfx-gma-config-ads): $(dir)/hw-gfx-gma-config.ads.template $(cnf) $< >$@ gfxinit-gen-y += $(hw-gfx-gma-config-ads) -ifneq ($(filter Ironlake Sandybridge Ivybridge,$(CONFIG_GFX_GMA_CPU)),) +ifneq ($(filter G45,$(CONFIG_GFX_GMA_CPU)),) +subdirs-y += g45 +else ifneq ($(filter Ironlake Sandybridge Ivybridge,$(CONFIG_GFX_GMA_CPU)),) subdirs-y += ironlake else ifneq ($(filter Haswell Broadwell,$(CONFIG_GFX_GMA_CPU)),) subdirs-y += haswell_shared haswell diff --git a/common/g45/Makefile.inc b/common/g45/Makefile.inc new file mode 100644 index 0000000000..6b598cbad6 --- /dev/null +++ b/common/g45/Makefile.inc @@ -0,0 +1,15 @@ +gfxinit-y += hw-gfx-gma-connectors.adb +gfxinit-y += hw-gfx-gma-gmch-dp.adb +gfxinit-y += hw-gfx-gma-gmch-dp.ads +gfxinit-y += hw-gfx-gma-gmch-hdmi.adb +gfxinit-y += hw-gfx-gma-gmch-hdmi.ads +gfxinit-y += hw-gfx-gma-gmch-lvds.adb +gfxinit-y += hw-gfx-gma-gmch-lvds.ads +gfxinit-y += hw-gfx-gma-gmch-vga.adb +gfxinit-y += hw-gfx-gma-gmch-vga.ads +gfxinit-y += hw-gfx-gma-plls.adb +gfxinit-y += hw-gfx-gma-plls.ads +gfxinit-y += hw-gfx-gma-port_detect.adb +gfxinit-y += hw-gfx-gma-gmch.ads +gfxinit-y += hw-gfx-gma-power_and_clocks.ads +gfxinit-y += hw-gfx-gma-power_and_clocks.adb \ No newline at end of file diff --git a/common/g45/hw-gfx-gma-connectors.adb b/common/g45/hw-gfx-gma-connectors.adb new file mode 100644 index 0000000000..5ca7c9be10 --- /dev/null +++ b/common/g45/hw-gfx-gma-connectors.adb @@ -0,0 +1,127 @@ +-- +-- Copyright (C) 2015-2016 secunet Security Networks AG +-- Copyright (C) 2016 Nico Huber +-- +-- 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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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 HW.GFX.GMA.Config; +with HW.GFX.GMA.Panel; +with HW.GFX.GMA.GMCH.VGA; +with HW.GFX.GMA.GMCH.LVDS; +with HW.GFX.GMA.GMCH.HDMI; +with HW.GFX.GMA.GMCH.DP; + +with HW.Debug; +with GNAT.Source_Info; + +package body HW.GFX.GMA.Connectors +is + + procedure Post_Reset_Off is null; + procedure Initialize is null; + + function Is_Internal (Port_Cfg : Port_Config) return Boolean + is + begin + return Port_Cfg.Port = LVDS; + end Is_Internal; + + ---------------------------------------------------------------------------- + + procedure Pre_On + (Pipe : in Pipe_Index; + Port_Cfg : in Port_Config; + PLL_Hint : in Word32; + Success : out Boolean) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + Success := True; + end Pre_On; + + procedure Post_On + (Pipe : in Pipe_Index; + Port_Cfg : in Port_Config; + PLL_Hint : in Word32; + Success : out Boolean) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + Success := True; + if Port_Cfg.Port = LVDS then + GMCH.LVDS.On (Port_Cfg, Pipe); + elsif Port_Cfg.Port = VGA then + GMCH.VGA.On (Pipe, Port_Cfg.Mode); + elsif Port_Cfg.Port in Digital_Port then + if Port_Cfg.Display = DP and Port_Cfg.Port in GMCH_DP_Port then + GMCH.DP.On (Port_Cfg, Pipe, Success); + elsif Port_Cfg.Display = HDMI and Port_Cfg.Port in GMCH_HDMI_Port then + GMCH.HDMI.On (Port_Cfg, Pipe); + end if; + end if; + + if Is_Internal (Port_Cfg) then + Panel.On (Wait => False); + Panel.Backlight_On; + end if; + end Post_On; + + ---------------------------------------------------------------------------- + + procedure Pre_Off (Port_Cfg : Port_Config) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + if Is_Internal (Port_Cfg) then + Panel.Backlight_Off; + Panel.Off; + end if; + end Pre_Off; + + procedure Post_Off (Port_Cfg : Port_Config) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + if Port_Cfg.Port = LVDS then + GMCH.LVDS.Off; + elsif Port_Cfg.Port = VGA then + GMCH.VGA.Off; + elsif Port_Cfg.Display = DP and Port_Cfg.Port in GMCH_DP_Port then + GMCH.DP.Off (Port_Cfg.Port); + elsif Port_Cfg.Display = HDMI and Port_Cfg.Port in GMCH_HDMI_Port then + GMCH.HDMI.Off (Port_Cfg.Port); + end if; + end Post_Off; + + ---------------------------------------------------------------------------- + + procedure Pre_All_Off + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Panel.Backlight_Off; + Panel.Off; + end Pre_All_Off; + + procedure Post_All_Off + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + GMCH.LVDS.Off; + GMCH.VGA.Off; + GMCH.DP.All_Off; + GMCH.HDMI.All_Off; + end Post_All_Off; + +end HW.GFX.GMA.Connectors; diff --git a/common/g45/hw-gfx-gma-gmch-dp.adb b/common/g45/hw-gfx-gma-gmch-dp.adb new file mode 100644 index 0000000000..8cc7f10ec9 --- /dev/null +++ b/common/g45/hw-gfx-gma-gmch-dp.adb @@ -0,0 +1,216 @@ +-- +-- Copyright (C) 2016 Nico Huber +-- +-- 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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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 HW.GFX.DP_Training; +with HW.GFX.GMA.DP_Aux_Ch; +with HW.GFX.GMA.DP_Info; +with HW.GFX.GMA.Registers; + +with HW.Debug; +with GNAT.Source_Info; + +package body HW.GFX.GMA.GMCH.DP is + + type DP_Array is array (GMCH_DP_Port) of Registers.Registers_Index; + DP_CTL : constant DP_Array := + (DIGI_B => Registers.GMCH_DP_B, + DIGI_C => Registers.GMCH_DP_C, + DIGI_D => Registers.GMCH_DP_D); + + DP_CTL_DISPLAY_PORT_ENABLE : constant := 1 * 2 ** 31; + DP_CTL_VSWING_LEVEL_SET_SHIFT : constant := 25; + DP_CTL_VSWING_LEVEL_SET_MASK : constant := 7 * 2 ** 25; + DP_CTL_PREEMPH_LEVEL_SET_SHIFT : constant := 22; + DP_CTL_PREEMPH_LEVEL_SET_MASK : constant := 7 * 2 ** 22; + DP_CTL_PORT_WIDTH_SHIFT : constant := 19; + DP_CTL_ENHANCED_FRAMING_ENABLE : constant := 1 * 2 ** 18; + DP_CTL_PORT_REVERSAL : constant := 1 * 2 ** 15; + DP_CTL_LINK_TRAIN_MASK : constant := 3 * 2 ** 28; + DP_CTL_LINK_TRAIN_PAT1 : constant := 0 * 2 ** 28; + DP_CTL_LINK_TRAIN_PAT2 : constant := 1 * 2 ** 28; + DP_CTL_LINK_TRAIN_IDLE : constant := 2 * 2 ** 28; + DP_CTL_LINK_TRAIN_NORMAL : constant := 3 * 2 ** 28; + DP_CTL_AUDIO_OUTPUT_ENABLE : constant := 1 * 2 ** 6; + DP_CTL_PORT_DETECT : constant := 1 * 2 ** 2; + DP_CTL_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 4; + DP_CTL_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 3; + DP_CTL_COLOR_RANGE_16_235 : constant := 1 * 2 ** 8; + DP_CTL_SCRAMBLE_DISABLE : constant := 1 * 2 ** 7; + + function DP_CTL_VSWING_LEVEL_SET + (VS : DP_Info.DP_Voltage_Swing) + return Word32 + is + begin + return Shift_Left(Word32 (DP_Info.DP_Voltage_Swing'Pos (VS)), 25); + end DP_CTL_VSWING_LEVEL_SET; + + function DP_CTL_PREEMPH_LEVEL_SET (PE : DP_Info.DP_Pre_Emph) return Word32 + is + begin + return Shift_Left(Word32 (DP_Info.DP_Pre_Emph'Pos (PE)), 22); + end DP_CTL_PREEMPH_LEVEL_SET; + + function DP_CTL_PORT_WIDTH (Lane_Count : DP_Lane_Count) return Word32 + is + begin + return Shift_Left(Word32 (Lane_Count_As_Integer (Lane_Count)) - 1, 19); + end DP_CTL_PORT_WIDTH; + + type DP_CTL_LINK_TRAIN_Array is array (DP_Info.Training_Pattern) of Word32; + DP_CTL_LINK_TRAIN : constant DP_CTL_LINK_TRAIN_Array := + (DP_Info.TP_1 => 0 * 2 ** 28, + DP_Info.TP_2 => 1 * 2 ** 28, + DP_Info.TP_3 => 1 * 2 ** 28, + DP_Info.TP_Idle => 2 * 2 ** 28, + DP_Info.TP_None => 3 * 2 ** 28); + + ---------------------------------------------------------------------------- + + pragma Warnings (GNATprove, Off, "unused variable ""Port""", + Reason => "Needed for a common interface"); + function Max_V_Swing + (Port : GMCH_DP_Port) + return DP_Info.DP_Voltage_Swing + is + begin + return DP_Info.VS_Level_3; + end Max_V_Swing; + + function Max_Pre_Emph + (Port : GMCH_DP_Port; + Train_Set : DP_Info.Train_Set) + return DP_Info.DP_Pre_Emph + is + begin + return + (case Train_Set.Voltage_Swing is + when DP_Info.VS_Level_0 => DP_Info.Emph_Level_3, + when DP_Info.VS_Level_1 => DP_Info.Emph_Level_2, + when DP_Info.VS_Level_2 => DP_Info.Emph_Level_1, + when DP_Info.VS_Level_3 => DP_Info.Emph_Level_0); + end Max_Pre_Emph; + + ---------------------------------------------------------------------------- + + pragma Warnings (GNATprove, Off, "unused variable ""Link""", + Reason => "Needed for a common interface"); + procedure Set_Training_Pattern + (Port : GMCH_DP_Port; + Link : DP_Link; + Pattern : DP_Info.Training_Pattern) + is + begin + Registers.Unset_And_Set_Mask + (Register => DP_CTL (Port), + Mask_Unset => DP_CTL_LINK_TRAIN_MASK, + Mask_Set => DP_CTL_LINK_TRAIN (Pattern)); + end Set_Training_Pattern; + + procedure Set_Signal_Levels + (Port : GMCH_DP_Port; + Link : DP_Link; + Train_Set : DP_Info.Train_Set) + is + begin + Registers.Unset_And_Set_Mask + (Register => DP_CTL (Port), + Mask_Unset => DP_CTL_VSWING_LEVEL_SET_MASK or + DP_CTL_PREEMPH_LEVEL_SET_MASK, + Mask_Set => DP_CTL_VSWING_LEVEL_SET (Train_Set.Voltage_Swing) or + DP_CTL_PREEMPH_LEVEL_SET (Train_Set.Pre_Emph)); + end Set_Signal_Levels; + + procedure Off (Port : GMCH_DP_Port) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Registers.Unset_And_Set_Mask + (Register => DP_CTL (Port), + Mask_Unset => DP_CTL_LINK_TRAIN_MASK, + Mask_Set => DP_CTL_LINK_TRAIN_IDLE); + Registers.Posting_Read (DP_CTL (Port)); + + Registers.Write (DP_CTL (Port), 0); + Registers.Posting_Read (DP_CTL (Port)); + end Off; + pragma Warnings (GNATprove, On, "unused variable ""Port"""); + pragma Warnings (GNATprove, On, "unused variable ""Link"""); + + ---------------------------------------------------------------------------- + + procedure On + (Port_Cfg : in Port_Config; + Pipe : in Pipe_Index; + Success : out Boolean) + is + function To_DP (Port : GMCH_DP_Port) return DP_Port + is + begin + return + (case Port is + when DIGI_B => DP_B, + when DIGI_C => DP_C, + when DIGI_D => DP_D); + end To_DP; + package Training is new DP_Training + (TPS3_Supported => False, + T => GMCH_DP_Port, + Aux_T => DP_Port, + Aux_Ch => DP_Aux_Ch, + DP_Info => DP_Info, + To_Aux => To_DP, + Max_V_Swing => Max_V_Swing, + Max_Pre_Emph => Max_Pre_Emph, + Set_Pattern => Set_Training_Pattern, + Set_Signal_Levels => Set_Signal_Levels, + Off => Off); + + Sync_Polarity : constant Word32 := + (if Port_Cfg.Mode.H_Sync_Active_High then DP_CTL_HSYNC_ACTIVE_HIGH else 0) or + (if Port_Cfg.Mode.V_Sync_Active_High then DP_CTL_VSYNC_ACTIVE_HIGH else 0); + + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Registers.Write + (Register => DP_CTL (Port_Cfg.Port), + Value => DP_CTL_DISPLAY_PORT_ENABLE or + DP_CTL_PORT_WIDTH (Port_Cfg.DP.Lane_Count) or + DP_CTL_LINK_TRAIN_PAT1 or + (if Port_Cfg.DP.Enhanced_Framing + then DP_CTL_ENHANCED_FRAMING_ENABLE else 0) or + GMCH_PORT_PIPE_SELECT(Pipe) or + Sync_Polarity or + DP_CTL_COLOR_RANGE_16_235); + Training.Train_DP + (Port => Port_Cfg.Port, + Link => Port_Cfg.DP, + Success => Success); + end On; + + ---------------------------------------------------------------------------- + + procedure All_Off + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + for Port in GMCH_DP_Port loop + Off (Port); + end loop; + end All_Off; + +end HW.GFX.GMA.GMCH.DP; diff --git a/common/g45/hw-gfx-gma-gmch-dp.ads b/common/g45/hw-gfx-gma-gmch-dp.ads new file mode 100644 index 0000000000..a99b603b57 --- /dev/null +++ b/common/g45/hw-gfx-gma-gmch-dp.ads @@ -0,0 +1,28 @@ +-- +-- Copyright (C) 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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- + +package HW.GFX.GMA.GMCH.DP +is + + procedure On + (Port_Cfg : in Port_Config; + Pipe : in Pipe_Index; + Success : out Boolean) + with + Pre => Port_Cfg.Port in GMCH_DP_Port; + + procedure Off (Port : GMCH_DP_Port); + procedure All_Off; + +end HW.GFX.GMA.GMCH.DP; diff --git a/common/g45/hw-gfx-gma-gmch-hdmi.adb b/common/g45/hw-gfx-gma-gmch-hdmi.adb new file mode 100644 index 0000000000..4c84f36d7f --- /dev/null +++ b/common/g45/hw-gfx-gma-gmch-hdmi.adb @@ -0,0 +1,97 @@ +-- +-- Copyright (C) 2015-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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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 HW.GFX.GMA.Registers; + +with HW.Debug; +with GNAT.Source_Info; + +package body HW.GFX.GMA.GMCH.HDMI +is + + GMCH_HDMI_ENABLE : constant := 1 * 2 ** 31; + GMCH_HDMI_COLOR_FORMAT_8BPC : constant := 0 * 2 ** 26; + GMCH_HDMI_COLOR_FORMAT_12BPC : constant := 3 * 2 ** 26; + GMCH_HDMI_COLOR_FORMAT_MASK : constant := 7 * 2 ** 26; + GMCH_HDMI_SDVO_ENCODING_SDVO : constant := 0 * 2 ** 10; + GMCH_HDMI_SDVO_ENCODING_HDMI : constant := 2 * 2 ** 10; + GMCH_HDMI_SDVO_ENCODING_MASK : constant := 3 * 2 ** 10; + GMCH_HDMI_MODE_SELECT_HDMI : constant := 1 * 2 ** 9; + GMCH_HDMI_MODE_SELECT_DVI : constant := 0 * 2 ** 9; + GMCH_HDMI_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 4; + GMCH_HDMI_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 3; + GMCH_HDMI_PORT_DETECT : constant := 1 * 2 ** 2; + + GMCH_HDMI_MASK : constant Word32 := + GMCH_PORT_PIPE_SELECT_MASK or + GMCH_HDMI_ENABLE or + GMCH_HDMI_COLOR_FORMAT_MASK or + GMCH_HDMI_SDVO_ENCODING_MASK or + GMCH_HDMI_MODE_SELECT_HDMI or + GMCH_HDMI_HSYNC_ACTIVE_HIGH or + GMCH_HDMI_VSYNC_ACTIVE_HIGH; + + type GMCH_HDMI_Array is array (GMCH_HDMI_Port) of Registers.Registers_Index; + GMCH_HDMI : constant GMCH_HDMI_Array := GMCH_HDMI_Array' + (DIGI_B => Registers.GMCH_HDMIB, + DIGI_C => Registers.GMCH_HDMIC); + + ---------------------------------------------------------------------------- + + procedure On (Port_Cfg : in Port_Config; + Pipe : in Pipe_Index) + is + Polarity : constant Word32 := + (if Port_Cfg.Mode.H_Sync_Active_High then + GMCH_HDMI_HSYNC_ACTIVE_HIGH else 0) or + (if Port_Cfg.Mode.V_Sync_Active_High then + GMCH_HDMI_VSYNC_ACTIVE_HIGH else 0); + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Registers.Unset_And_Set_Mask + (Register => GMCH_HDMI (Port_Cfg.Port), + Mask_Unset => GMCH_HDMI_MASK, + Mask_Set => GMCH_HDMI_ENABLE or + GMCH_PORT_PIPE_SELECT (Pipe) or + GMCH_HDMI_SDVO_ENCODING_HDMI or + GMCH_HDMI_MODE_SELECT_HDMI or + Polarity); + end On; + + ---------------------------------------------------------------------------- + + procedure Off (Port : GMCH_HDMI_Port) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Registers.Unset_And_Set_Mask + (Register => GMCH_HDMI (Port), + Mask_Unset => GMCH_HDMI_MASK, + Mask_Set => GMCH_HDMI_HSYNC_ACTIVE_HIGH or + GMCH_HDMI_VSYNC_ACTIVE_HIGH); + end Off; + + procedure All_Off + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + for Port in GMCH_HDMI_Port loop + Off (Port); + end loop; + end All_Off; + +end HW.GFX.GMA.GMCH.HDMI; diff --git a/common/g45/hw-gfx-gma-gmch-hdmi.ads b/common/g45/hw-gfx-gma-gmch-hdmi.ads new file mode 100644 index 0000000000..3905f0c238 --- /dev/null +++ b/common/g45/hw-gfx-gma-gmch-hdmi.ads @@ -0,0 +1,26 @@ +-- +-- Copyright (C) 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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- + +package HW.GFX.GMA.GMCH.HDMI +is + + procedure On (Port_Cfg : in Port_Config; + Pipe : in Pipe_Index) + with + Pre => Port_Cfg.Port in GMCH_HDMI_Port; + + procedure Off (Port : GMCH_HDMI_Port); + procedure All_Off; + +end HW.GFX.GMA.GMCH.HDMI; diff --git a/common/g45/hw-gfx-gma-gmch-lvds.adb b/common/g45/hw-gfx-gma-gmch-lvds.adb new file mode 100644 index 0000000000..746f8c19d8 --- /dev/null +++ b/common/g45/hw-gfx-gma-gmch-lvds.adb @@ -0,0 +1,81 @@ +-- +-- Copyright (C) 2015-2016 secunet Security Networks AG +-- Copyright (C) 2016 Nico Huber +-- +-- 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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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 HW.GFX.GMA.Config; +with HW.GFX.GMA.Registers; + +with HW.Debug; +with GNAT.Source_Info; + +package body HW.GFX.GMA.GMCH.LVDS is + + LVDS_ENABLE : constant := 1 * 2 ** 31; + LVDS_DITHER_EN : constant := 1 * 2 ** 25; + LVDS_VSYNC_POLARITY_INVERT : constant := 1 * 2 ** 21; + LVDS_HSYNC_POLARITY_INVERT : constant := 1 * 2 ** 20; + LVDS_CLK_A_DATA_A0A2_POWER_MASK : constant := 3 * 2 ** 8; + LVDS_CLK_A_DATA_A0A2_POWER_DOWN : constant := 0 * 2 ** 8; + LVDS_CLK_A_DATA_A0A2_POWER_UP : constant := 3 * 2 ** 8; + LVDS_CLK_B_POWER_MASK : constant := 3 * 2 ** 4; + LVDS_CLK_B_POWER_DOWN : constant := 0 * 2 ** 4; + LVDS_CLK_B_POWER_UP : constant := 3 * 2 ** 4; + LVDS_DATA_B0B2_POWER_MASK : constant := 3 * 2 ** 2; + LVDS_DATA_B0B2_POWER_DOWN : constant := 0 * 2 ** 2; + LVDS_DATA_B0B2_POWER_UP : constant := 3 * 2 ** 2; + + ---------------------------------------------------------------------------- + + procedure On (Port_Cfg : in Port_Config; + Pipe : in Pipe_Index) + is + Sync_Polarity : constant Word32 := + (if Port_Cfg.Mode.H_Sync_Active_High then 0 + else LVDS_HSYNC_POLARITY_INVERT) or + (if Port_Cfg.Mode.V_Sync_Active_High then 0 + else LVDS_VSYNC_POLARITY_INVERT); + + Two_Channel : constant Word32 := + (if Port_Cfg.Mode.Dotclock >= Config.LVDS_Dual_Threshold then + LVDS_CLK_B_POWER_UP or LVDS_DATA_B0B2_POWER_UP else 0); + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + pragma Debug (Port_Cfg.Mode.BPC /= 6, Debug.Put_Line + ("WARNING: Only 18bpp LVDS mode implemented.")); + + Registers.Write + (Register => Registers.GMCH_LVDS, + Value => LVDS_ENABLE or + GMCH_PORT_PIPE_SELECT(Pipe) or + Sync_Polarity or + LVDS_CLK_A_DATA_A0A2_POWER_UP or + Two_Channel or + LVDS_DITHER_EN); + end On; + + ---------------------------------------------------------------------------- + + procedure Off + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Registers.Write + (Register => Registers.GMCH_LVDS, + Value => LVDS_CLK_A_DATA_A0A2_POWER_DOWN or + LVDS_CLK_B_POWER_DOWN or + LVDS_DATA_B0B2_POWER_DOWN); + end Off; + +end HW.GFX.GMA.GMCH.LVDS; diff --git a/common/g45/hw-gfx-gma-gmch-lvds.ads b/common/g45/hw-gfx-gma-gmch-lvds.ads new file mode 100644 index 0000000000..c477a4070b --- /dev/null +++ b/common/g45/hw-gfx-gma-gmch-lvds.ads @@ -0,0 +1,23 @@ +-- +-- Copyright (C) 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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- + +package HW.GFX.GMA.GMCH.LVDS +is + + procedure On (Port_Cfg : in Port_Config; + Pipe : in Pipe_Index); + + procedure Off; + +end HW.GFX.GMA.GMCH.LVDS; diff --git a/common/g45/hw-gfx-gma-gmch-vga.adb b/common/g45/hw-gfx-gma-gmch-vga.adb new file mode 100644 index 0000000000..92f489b8ba --- /dev/null +++ b/common/g45/hw-gfx-gma-gmch-vga.adb @@ -0,0 +1,80 @@ +-- +-- Copyright (C) 2015-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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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 HW.GFX.GMA.Config; +with HW.GFX.GMA.Registers; + +with HW.Debug; +with GNAT.Source_Info; + +use type HW.Word64; + +package body HW.GFX.GMA.GMCH.VGA is + + ADPA_DAC_ENABLE : constant := 1 * 2 ** 31; + ADPA_USE_VGA_HVPOLARITY : constant := 1 * 2 ** 15; + ADPA_VSYNC_DISABLE : constant := 1 * 2 ** 11; + ADPA_HSYNC_DISABLE : constant := 1 * 2 ** 10; + ADPA_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 4; + ADPA_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 3; + + ADPA_MASK : constant Word32 := + GMCH_PORT_PIPE_SELECT_MASK or + ADPA_DAC_ENABLE or + ADPA_VSYNC_DISABLE or + ADPA_HSYNC_DISABLE or + ADPA_VSYNC_ACTIVE_HIGH or + ADPA_HSYNC_ACTIVE_HIGH or + ADPA_USE_VGA_HVPOLARITY; + + ---------------------------------------------------------------------------- + + procedure On + (Pipe : Pipe_Index; + Mode : in Mode_Type) + is + Polarity : Word32 := 0; + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + if Mode.H_Sync_Active_High then + Polarity := Polarity or ADPA_HSYNC_ACTIVE_HIGH; + end if; + if Mode.V_Sync_Active_High then + Polarity := Polarity or ADPA_VSYNC_ACTIVE_HIGH; + end if; + + Registers.Unset_And_Set_Mask + (Register => Registers.GMCH_ADPA, + Mask_Unset => ADPA_MASK, + Mask_Set => ADPA_DAC_ENABLE or + GMCH_PORT_PIPE_SELECT (Pipe) or + Polarity); + end On; + + ---------------------------------------------------------------------------- + + procedure Off + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Registers.Unset_And_Set_Mask + (Register => Registers.GMCH_ADPA, + Mask_Unset => ADPA_DAC_ENABLE, + Mask_Set => ADPA_HSYNC_DISABLE or + ADPA_VSYNC_DISABLE); + end Off; + +end HW.GFX.GMA.GMCH.VGA; diff --git a/common/g45/hw-gfx-gma-gmch-vga.ads b/common/g45/hw-gfx-gma-gmch-vga.ads new file mode 100644 index 0000000000..8a4e934ba9 --- /dev/null +++ b/common/g45/hw-gfx-gma-gmch-vga.ads @@ -0,0 +1,22 @@ +-- +-- Copyright (C) 2015-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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- + +package HW.GFX.GMA.GMCH.VGA is + + procedure On + (Pipe : in Pipe_Index; + Mode : in Mode_Type); + procedure Off; + +end HW.GFX.GMA.GMCH.VGA; diff --git a/common/g45/hw-gfx-gma-gmch.ads b/common/g45/hw-gfx-gma-gmch.ads new file mode 100644 index 0000000000..0e7832cac9 --- /dev/null +++ b/common/g45/hw-gfx-gma-gmch.ads @@ -0,0 +1,13 @@ +with HW.GFX.GMA.Config; + +private package HW.GFX.GMA.GMCH is + + GMCH_PORT_PIPE_SELECT_SHIFT : constant := 30; + GMCH_PORT_PIPE_SELECT_MASK : constant := 1 * 2 ** 30; + type GMCH_PORT_PIPE_SELECT_Array is array (Pipe_Index) of Word32; + GMCH_PORT_PIPE_SELECT : constant GMCH_PORT_PIPE_SELECT_Array := + (Primary => 0 * 2 ** GMCH_PORT_PIPE_SELECT_SHIFT, + Secondary => 1 * 2 ** GMCH_PORT_PIPE_SELECT_SHIFT, + Tertiary => 0); + +end HW.GFX.GMA.GMCH; diff --git a/common/g45/hw-gfx-gma-plls.adb b/common/g45/hw-gfx-gma-plls.adb new file mode 100644 index 0000000000..67242f2d5b --- /dev/null +++ b/common/g45/hw-gfx-gma-plls.adb @@ -0,0 +1,603 @@ +-- +-- Copyright (C) 2015-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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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 HW.Time; +with HW.GFX.GMA.Config; +with HW.GFX.GMA.Registers; + +with HW.Debug; +with GNAT.Source_Info; + +package body HW.GFX.GMA.PLLs +with + Refined_State => (State => PLLs) +is + + Debug_Clocks : constant Boolean := False; + + type Count_Range is new Natural range 0 .. 2; + + type PLL_State is record + Use_Count : Count_Range; + Used_For_DP : Boolean; + Link_Rate : DP_Bandwidth; + Mode : Mode_Type; + end record; + + type PLL_State_Array is array (DPLLs) of PLL_State; + + PLLs : PLL_State_Array; + + ---------------------------------------------------------------------------- + + subtype N_Range is Int64 range 3 .. 8; + subtype M_Range is Int64 range 70 .. 138; + subtype M1_Range is Int64 range 10 .. 25; + subtype M2_Range is Int64 range 4 .. 13; + subtype P_Range is Int64 range 5 .. 112; + subtype P1_Range is Int64 range 1 .. 8; + subtype P2_Range is Int64 range 5 .. 14; + subtype VCO_Range is Int64 range 1400000000 .. 3500000000; + subtype Clock_Range is HW.GFX.Frequency_Type; + + type Clock_Type is + record + N : N_Range; + M1 : M1_Range; + M2 : M2_Range; + P1 : P1_Range; + P2 : P2_Range; + M : M_Range; + P : P_Range; + VCO : VCO_Range; + Reference_Clock : Clock_Range; + Dotclock : Clock_Range; + end record; + + Invalid_Clock : constant Clock_Type := Clock_Type' + (N => N_Range'Last, + M1 => M1_Range'Last, + M2 => M2_Range'Last, + P1 => P1_Range'Last, + P2 => P2_Range'Last, + Reference_Clock => Clock_Range'Last, + M => M_Range'Last, + P => P_Range'Last, + VCO => VCO_Range'Last, + Dotclock => Clock_Range'Last); + + type Limits_Type is + record + N_Lower : N_Range; + N_Upper : N_Range; + M_Lower : M_Range; + M_Upper : M_Range; + M1_Lower : M1_Range; + M1_Upper : M1_Range; + M2_Lower : M2_Range; + M2_Upper : M2_Range; + P_Lower : P_Range; + P_Upper : P_Range; + P1_Lower : P1_Range; + P1_Upper : P1_Range; + P2_Fast : P2_Range; + P2_Slow : P2_Range; + P2_Threshold : Clock_Range; + VCO_Lower : VCO_Range; + VCO_Upper : VCO_Range; + end record; + + LVDS_Single_Limits : constant Limits_Type := Limits_Type' + (N_Lower => 3, N_Upper => 5, + M_Lower => 104, M_Upper => 138, + M1_Lower => 19, M1_Upper => 25, -- this is capped by M_Upper >= 5 * M1 + M2_Lower + M2_Lower => 7, M2_Upper => 13, + P_Lower => 28, P_Upper => 112, + P1_Lower => 2, P1_Upper => 8, + P2_Fast => 14, P2_Slow => 14, + P2_Threshold => Clock_Range'First, + VCO_Lower => 1_750_000_000, VCO_Upper => 3_500_000_000); + LVDS_Dual_Limits : constant Limits_Type := Limits_Type' + (N_Lower => 3, N_Upper => 5, + M_Lower => 104, M_Upper => 138, + M1_Lower => 19, M1_Upper => 25, + M2_Lower => 7, M2_Upper => 13, + P_Lower => 14, P_Upper => 56, + P1_Lower => 2, P1_Upper => 6, + P2_Fast => 7, P2_Slow => 7, + P2_Threshold => Clock_Range'First, + VCO_Lower => 1_750_000_000, VCO_Upper => 3_500_000_000); + SDVO_Limits : constant Limits_Type := Limits_Type' + (N_Lower => 3, N_Upper => 6, + M_Lower => 104, M_Upper => 138, + M1_Lower => 16, M1_Upper => 25, + M2_Lower => 7, M2_Upper => 13, + P_Lower => 10, P_Upper => 30, + P1_Lower => 1, P1_Upper => 3, + -- use P2_Slow if Dotclock <= P2_Threshold, P2_Fast otherwise + P2_Fast => 5, P2_Slow => 10, + P2_Threshold => 270_000_000, + VCO_Lower => 1_750_000_000, VCO_Upper => 3_500_000_000); + HDMI_Analog_Limits : constant Limits_Type := Limits_Type' + (N_Lower => 3, N_Upper => 6, + M_Lower => 104, M_Upper => 138, + M1_Lower => 18, M1_Upper => 25, + M2_Lower => 7, M2_Upper => 13, + P_Lower => 5, P_Upper => 80, + P1_Lower => 1, P1_Upper => 8, + -- use P2_Slow if Dotclock <= P2_Threshold, P2_Fast otherwise + P2_Fast => 5, P2_Slow => 10, + P2_Threshold => 165_000_000, + VCO_Lower => 1_750_000_000, VCO_Upper => 3_500_000_000); + All_Other_Limits : constant Limits_Type := Limits_Type' + (N_Lower => 3, N_Upper => 8, + M_Lower => 70, M_Upper => 120, + M1_Lower => 10, M1_Upper => 20, + M2_Lower => 5, M2_Upper => 9, + P_Lower => 5, P_Upper => 80, + P1_Lower => 1, P1_Upper => 8, + -- use P2_Slow if Dotclock <= P2_Threshold, P2_Fast otherwise + P2_Fast => 5, P2_Slow => 10, + P2_Threshold => 200_000_000, + VCO_Lower => 1_400_000_000, VCO_Upper => 2_800_000_000); + + ---------------------------------------------------------------------------- + + type Regs is array (DPLLs) of Registers.Registers_Index; + + DPLL : constant Regs := Regs'(Registers.GMCH_DPLL_A, Registers.GMCH_DPLL_B); + DPLL_VCO_ENABLE : constant := 1 * 2 ** 31; + DPLL_VGA_MODE_DIS : constant := 1 * 2 ** 28; + DPLL_P2_10_OR_14 : constant := 0 * 2 ** 24; + DPLL_P2_5_OR_7 : constant := 1 * 2 ** 24; + DPLL_P1_DIVIDER_SHIFT : constant := 16; + DPLL_SDVOCLK : constant := 2 * 2 ** 13; + DPLL_PULSE_PHASE_MASK : constant := 15 * 2 ** 9; + DPLL_PULSE_PHASE_6 : constant := 6 * 2 ** 9; + + DPLL_HIGH_SPEED : constant := 1 * 2 ** 30; + DPLL_MODE_LVDS : constant := 2 * 2 ** 26; + DPLL_MODE_DAC : constant := 1 * 2 ** 26; + DPLL_DREFCLK : constant := 0 * 2 ** 13; + DPLL_SSC : constant := 3 * 2 ** 13; + + MODE_DPLL_DAC : constant Word32 := Word32' + (DPLL_MODE_DAC or DPLL_DREFCLK); + + MODE_DPLL_HDMI : constant Word32 := Word32' + (DPLL_MODE_DAC or DPLL_DREFCLK or DPLL_HIGH_SPEED); + + MODE_DPLL_LVDS : constant Word32 := Word32' + (DPLL_MODE_LVDS or DPLL_SSC); + + MODE_DPLL_DP : constant Word32 := Word32' + (DPLL_MODE_DAC or DPLL_SSC or DPLL_HIGH_SPEED); + + type DPLL_Mode_Array is array (Display_Type) of Word32; + + DPLL_Mode : constant DPLL_Mode_Array := DPLL_Mode_Array' + (LVDS => MODE_DPLL_LVDS, + DP => MODE_DPLL_DP, + HDMI => MODE_DPLL_HDMI, + VGA => MODE_DPLL_DAC, + Others => MODE_DPLL_HDMI); --TODO Add SDVO + + FP0 : constant Regs := Regs'(Registers.GMCH_FPA0, Registers.GMCH_FPB0); + FP1 : constant Regs := Regs'(Registers.GMCH_FPA1, Registers.GMCH_FPB1); + FP_DOUBLE_CLOCK : constant := 1 * 2 ** 27; + FP_N_SHIFT : constant := 16; + FP_M1_SHIFT : constant := 8; + FP_M2_SHIFT : constant := 0; + + ---------------------------------------------------------------------------- + + procedure Verify_Parameters + (N : in N_Range; + M1 : in M1_Range; + M2 : in M2_Range; + P1 : in P1_Range; + P2 : in P2_Range; + Reference_Clock : in Clock_Range; + Current_Limits : in Limits_Type; + Result : out Clock_Type; + Valid : out Boolean) + with + Global => null, + Pre => True, + Post => True + is + M : Int64; + P : Int64; + VCO : Int64; + Dotclock : Int64; + begin + pragma Debug (Debug_Clocks, Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + M := 5 * M1 + M2; + P := P1 * P2; + VCO := (Int64 (Reference_Clock) * M) / N; + Dotclock := VCO / P; + + pragma Debug (Debug_Clocks and not (Current_Limits.P1_Lower <= P1 and P1 <= Current_Limits.P1_Upper ), Debug.Put_Line ("P1 out of range.")); + pragma Debug (Debug_Clocks and (Current_Limits.P2_Fast /= P2 and P2 /= Current_Limits.P2_Slow ), Debug.Put_Line ("P2 out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.P_Lower <= P and P <= Current_Limits.P_Upper ), Debug.Put_Line ("P out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.M1_Lower <= M1 and M1 <= Current_Limits.M1_Upper ), Debug.Put_Line ("M1 out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.M2_Lower <= M2 and M2 <= Current_Limits.M2_Upper ), Debug.Put_Line ("M2 out of range.")); + -- pragma Debug (Debug_Clocks and not (M2 <= M1 ), Debug.Put_Line ("M1 greater thant M2.")); + pragma Debug (Debug_Clocks and not (Current_Limits.N_Lower <= N and N <= Current_Limits.N_Upper ), Debug.Put_Line ("N out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.M_Lower <= M and M <= Current_Limits.M_Upper ), Debug.Put_Line ("M out of range.")); + pragma Debug (Debug_Clocks and not (Current_Limits.VCO_Lower <= VCO and VCO <= Current_Limits.VCO_Upper), Debug.Put_Line ("VCO out of range.")); + + pragma Debug (Debug_Clocks and not (Int64 (Clock_Range'First) <= Dotclock), Debug.Put_Line ("Dotclock too low.")); + pragma Debug (Debug_Clocks and not (Int64 (Clock_Range'First) <= Dotclock), Debug.Put_Int64 (Dotclock)); + pragma Debug (Debug_Clocks and not (Int64 (Clock_Range'First) <= Dotclock), Debug.New_Line); + + pragma Debug (Debug_Clocks and not (Dotclock <= Int64 (Clock_Range'Last)), Debug.Put_Line ("Dotclock too high.")); + pragma Debug (Debug_Clocks and not (Dotclock <= Int64 (Clock_Range'Last)), Debug.Put_Int64 (Dotclock)); + pragma Debug (Debug_Clocks and not (Dotclock <= Int64 (Clock_Range'Last)), Debug.New_Line); + + Valid := + Current_Limits.P1_Lower <= P1 and P1 <= Current_Limits.P1_Upper and + (Current_Limits.P2_Fast = P2 or P2 = Current_Limits.P2_Slow) and + Current_Limits.P_Lower <= P and P <= Current_Limits.P_Upper and + Current_Limits.M1_Lower <= M1 and M1 <= Current_Limits.M1_Upper and + Current_Limits.M2_Lower <= M2 and M2 <= Current_Limits.M2_Upper and + Current_Limits.N_Lower <= N and N <= Current_Limits.N_Upper and + Current_Limits.M_Lower <= M and M <= Current_Limits.M_Upper and + Current_Limits.VCO_Lower <= VCO and VCO <= Current_Limits.VCO_Upper and + Int64 (Clock_Range'First) <= Dotclock and + Dotclock <= Int64 (Clock_Range'Last); + + if Valid + then + Result := Clock_Type' + (N => N, + M1 => M1, + M2 => M2, + P1 => P1, + P2 => P2, + Reference_Clock => Reference_Clock, + M => M, + P => P, + VCO => VCO, + Dotclock => Clock_Range (Dotclock)); + else + Result := Invalid_Clock; + end if; + + end Verify_Parameters; + + procedure Calculate_Clock_Parameters + (Display : in Display_Type; + Target_Dotclock : in Clock_Range; + Reference_Clock : in Clock_Range; + Best_Clock : out Clock_Type; + Valid : out Boolean) + with + Global => null, + Pre => True, + Post => True + is + Limits : constant Limits_Type := + (case Display is + when LVDS => + (if Target_Dotclock >= Config.LVDS_Dual_Threshold then + LVDS_Dual_Limits + else + LVDS_Single_Limits), + when HDMI => HDMI_Analog_Limits, + when VGA => HDMI_Analog_Limits, + when others => All_Other_Limits); --TODO add SDVO type, needs other limits + + P2 : P2_Range; + Best_Delta : Int64 := Int64'Last; + Current_Delta : Int64; + Current_Clock : Clock_Type; + Registers_Valid : Boolean; + begin + pragma Debug (Debug_Clocks, Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Valid := False; + Best_Clock := Invalid_Clock; + + if Target_Dotclock <= Limits.P2_Threshold then + P2 := Limits.P2_Slow; + else + P2 := Limits.P2_Fast; + end if; + + for N in N_Range range Limits.N_Lower .. Limits.N_Upper + loop + -- reverse loops as hardware prefers higher values + for M1 in reverse M1_Range range Limits.M1_Lower .. Limits.M1_Upper + loop + for M2 in reverse M2_Range range Limits.M2_Lower .. Int64'Min (Limits.M2_Upper, M1) + loop + for P1 in reverse P1_Range range Limits.P1_Lower .. Limits.P1_Upper + loop + Verify_Parameters + (N => N, + M1 => M1, + M2 => M2, + P1 => P1, + P2 => P2, + Reference_Clock => Reference_Clock, + Current_Limits => Limits, + Result => Current_Clock, + Valid => Registers_Valid); + + if Registers_Valid + then + if Current_Clock.Dotclock > Target_Dotclock + then + Current_Delta := Current_Clock.Dotclock - Target_Dotclock; + else + Current_Delta := Target_Dotclock - Current_Clock.Dotclock; + end if; + + if Current_Delta < Best_Delta + then + Best_Delta := Current_Delta; + Best_Clock := Current_Clock; + Valid := True; + end if; + + pragma Debug (Debug_Clocks, Debug.Put ("Current/Target/Best_Delta: ")); + pragma Debug (Debug_Clocks, Debug.Put_Int64 (Current_Clock.Dotclock)); + pragma Debug (Debug_Clocks, Debug.Put ("/")); + pragma Debug (Debug_Clocks, Debug.Put_Int64 (Target_Dotclock)); + pragma Debug (Debug_Clocks, Debug.Put ("/")); + pragma Debug (Debug_Clocks, Debug.Put_Int64 (Best_Delta)); + pragma Debug (Debug_Clocks, Debug.Put_Line (".")); + + end if; + end loop; + end loop; + end loop; + end loop; + + pragma Debug (Valid, Debug.Put_Line ("Valid clock found.")); + pragma Debug (Valid, Debug.Put ("Best/Target/Delta: ")); + pragma Debug (Valid, Debug.Put_Int64 (Best_Clock.Dotclock)); + pragma Debug (Valid, Debug.Put ("/")); + pragma Debug (Valid, Debug.Put_Int64 (Target_Dotclock)); + pragma Debug (Valid, Debug.Put ("/")); + pragma Debug (Valid, Debug.Put_Int64 (Best_Delta)); + pragma Debug (Valid, Debug.Put_Line (".")); + pragma Debug (not Valid, Debug.Put_Line ("No valid clock found.")); + + end Calculate_Clock_Parameters; + + procedure Program_DPLL + (PLL : DPLLs; + Display : Display_Type; + Clk : Clock_Type) + with + Global => (In_Out => Registers.Register_State), + Pre => True, + Post => True + is + FP, Encoded_P1, Encoded_P2 : Word32; + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + FP := + Shift_Left (Word32 (Clk.N - 2), FP_N_SHIFT) or + Shift_Left (Word32 (Clk.M1 - 2), FP_M1_SHIFT) or + Shift_Left (Word32 (Clk.M2 - 2), FP_M2_SHIFT); + + Registers.Write (FP0 (PLL), FP); + Registers.Write (FP1 (PLL), FP); + + Encoded_P1 := Shift_Left (1, Natural (Clk.P1) - 1); + + if Clk.P2 = 5 or Clk.P2 = 7 + then + Encoded_P2 := DPLL_P2_5_OR_7; + else + Encoded_P2 := DPLL_P2_10_OR_14; + end if; + + Registers.Write + (Register => DPLL (PLL), + Value => DPLL_Mode (Display) or + DPLL_VGA_MODE_DIS or + DPLL_PULSE_PHASE_6 or + Encoded_P2 or + Shift_Left (Encoded_P1, DPLL_P1_DIVIDER_SHIFT)); + end Program_DPLL; + + procedure On + (PLL : in T; + Port_Cfg : in Port_Config; + Success : out Boolean) + is + Target_Clock : constant Frequency_Type := + (if Port_Cfg.Display = DP then + DP_Symbol_Rate (Port_Cfg.DP.Bandwidth) + else + Port_Cfg.Mode.Dotclock); + Clk : Clock_Type; + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + Success := PLL in DPLLs; + Clk := Invalid_Clock; + + if Success then + if Port_Cfg.Display = DP then + Success := True; + -- we use static values for DP + case Port_Cfg.DP.Bandwidth is + when DP_Bandwidth_1_62 => + Clk.N := 4; + Clk.M1 := 25; + Clk.M2 := 10; + Clk.P1 := 2; + Clk.P2 := 10; + when DP_Bandwidth_2_7 => + Clk.N := 3; + Clk.M1 := 16; + Clk.M2 := 4; + Clk.P1 := 1; + Clk.P2 := 10; + when others => + Success := False; + end case; + elsif Target_Clock <= 340_000_000 then + Calculate_Clock_Parameters + (Display => Port_Cfg.Display, + Target_Dotclock => Target_Clock, + -- should be, but doesn't has to be always the same: + Reference_Clock => 96_000_000, + Best_Clock => Clk, + Valid => Success); + else + Success := False; + pragma Debug (Debug.Put ("WARNING: Targeted clock too high: ")); + pragma Debug (Debug.Put_Int64 (Target_Clock)); + pragma Debug (Debug.Put (" > ")); + pragma Debug (Debug.Put_Int32 (340_000_000)); + pragma Debug (Debug.New_Line); + pragma Debug (Debug.New_Line); + end if; + end if; + + if Success then + Program_DPLL (PLL, Port_Cfg.Display, Clk); + + Registers.Set_Mask (DPLL (PLL), DPLL_VCO_ENABLE); + Registers.Posting_Read (DPLL (PLL)); + Time.U_Delay (150); + end if; + end On; + + procedure Off (PLL : T) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + if PLL in DPLLs then + Registers.Unset_Mask (DPLL (PLL), DPLL_VCO_ENABLE); + end if; + end Off; + + ---------------------------------------------------------------------------- + + procedure Initialize + is + begin + PLLs := + (DPLLs => + (Use_Count => 0, + Used_For_DP => False, + Link_Rate => DP_Bandwidth'First, + Mode => Invalid_Mode)); + end Initialize; + + procedure Alloc_Configurable + (Port_Cfg : in Port_Config; + PLL : out T; + Success : out Boolean) + with + Pre => True + is + function Config_Matches (PE : PLL_State) return Boolean + is + begin + return + PE.Used_For_DP = (Port_Cfg.Display = DP) and + ((PE.Used_For_DP and PE.Link_Rate = Port_Cfg.DP.Bandwidth) or + (not PE.Used_For_DP and PE.Mode = Port_Cfg.Mode)); + end Config_Matches; + begin + -- try to find shareable PLL + for P in DPLLs loop + Success := PLLs (P).Use_Count /= 0 and + PLLs (P).Use_Count /= Count_Range'Last and + Config_Matches (PLLs (P)); + if Success then + PLL := P; + PLLs (PLL).Use_Count := PLLs (PLL).Use_Count + 1; + return; + end if; + end loop; + + -- try to find free PLL + for P in DPLLs loop + if PLLs (P).Use_Count = 0 then + PLL := P; + On (PLL, Port_Cfg, Success); + if Success then + PLLs (PLL) := + (Use_Count => 1, + Used_For_DP => Port_Cfg.Display = DP, + Link_Rate => Port_Cfg.DP.Bandwidth, + Mode => Port_Cfg.Mode); + end if; + return; + end if; + end loop; + + PLL := Invalid; + end Alloc_Configurable; + + procedure Alloc + (Port_Cfg : in Port_Config; + PLL : out T; + Success : out Boolean) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + if Port_Cfg.Port = DIGI_A then + PLL := Invalid; + Success := True; + else + Alloc_Configurable (Port_Cfg, PLL, Success); + end if; + end Alloc; + + procedure Free (PLL : T) + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + if PLL in DPLLs then + if PLLs (PLL).Use_Count /= 0 then + PLLs (PLL).Use_Count := PLLs (PLL).Use_Count - 1; + if PLLs (PLL).Use_Count = 0 then + Off (PLL); + end if; + end if; + end if; + end Free; + + procedure All_Off + is + begin + pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity)); + + for PLL in DPLLs loop + Off (PLL); + end loop; + end All_Off; + + function Register_Value (PLL : T) return Word32 + is + begin + return (if PLL = DPLL_B then 1 else 0); + end Register_Value; + +end HW.GFX.GMA.PLLs; diff --git a/common/g45/hw-gfx-gma-plls.ads b/common/g45/hw-gfx-gma-plls.ads new file mode 100644 index 0000000000..09d694612f --- /dev/null +++ b/common/g45/hw-gfx-gma-plls.ads @@ -0,0 +1,40 @@ +-- +-- Copyright (C) 2015-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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- + +private package HW.GFX.GMA.PLLs +with + Abstract_State => (State with Part_Of => GMA.State) +is + + -- XXX: Types should be private (but that triggers a bug in SPARK GPL 2016) + type T is (Invalid_PLL, DPLL_A, DPLL_B); + subtype DPLLs is T range DPLL_A .. DPLL_B; + Invalid : constant T := Invalid_PLL; + + procedure Initialize + with + Global => (Output => State); + + procedure Alloc + (Port_Cfg : in Port_Config; + PLL : out T; + Success : out Boolean); + + procedure Free (PLL : T); + + procedure All_Off; + + function Register_Value (PLL : T) return Word32; + +end HW.GFX.GMA.PLLs; diff --git a/common/g45/hw-gfx-gma-port_detect.adb b/common/g45/hw-gfx-gma-port_detect.adb new file mode 100644 index 0000000000..c865079695 --- /dev/null +++ b/common/g45/hw-gfx-gma-port_detect.adb @@ -0,0 +1,124 @@ +-- +-- Copyright (C) 2016-2017 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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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 HW.GFX.GMA.Config; +with HW.GFX.GMA.Registers; +with HW.GFX.GMA.Config_Helpers; + +package body HW.GFX.GMA.Port_Detect +is + + PORT_DETECTED : constant := 1 * 2 ** 2; + + PORTB_HOTPLUG_INT_EN : constant := 1 * 2 ** 29; + PORTC_HOTPLUG_INT_EN : constant := 1 * 2 ** 28; + PORTD_HOTPLUG_INT_EN : constant := 1 * 2 ** 27; + SDVOB_HOTPLUG_INT_EN : constant := 1 * 2 ** 26; + SDVOC_HOTPLUG_INT_EN : constant := 1 * 2 ** 25; + CRT_HOTPLUG_INT_EN : constant := 1 * 2 ** 9; + CRT_HOTPLUG_ACTIVATION_PERIOD_64 : constant := 1 * 2 ** 8; + + type HDMI_Port_Value is array (GMCH_HDMI_Port) of Word32; + type DP_Port_Value is array (GMCH_DP_Port) of Word32; + HDMI_PORT_HOTPLUG_EN : constant HDMI_Port_Value := + (DIGI_B => SDVOB_HOTPLUG_INT_EN, + DIGI_C => SDVOC_HOTPLUG_INT_EN); + DP_PORT_HOTPLUG_EN : constant DP_Port_Value := + (DIGI_B => PORTB_HOTPLUG_INT_EN, + DIGI_C => PORTC_HOTPLUG_INT_EN, + DIGI_D => PORTD_HOTPLUG_INT_EN); + + type HDMI_Regs is array (GMCH_HDMI_Port) of Registers.Registers_Index; + type DP_Regs is array (GMCH_DP_Port) of Registers.Registers_Index; + GMCH_HDMI : constant HDMI_Regs := + (DIGI_B => Registers.GMCH_HDMIB, + DIGI_C => Registers.GMCH_HDMIC); + GMCH_DP : constant DP_Regs := + (DIGI_B => Registers.GMCH_DP_B, + DIGI_C => Registers.GMCH_DP_C, + DIGI_D => Registers.GMCH_DP_D); + + HOTPLUG_INT_STATUS : constant array (Active_Port_Type) of word32 := + (DP1 => 3 * 2 ** 17, + DP2 => 3 * 2 ** 19, + DP3 => 3 * 2 ** 21, + HDMI1 => 1 * 2 ** 2, + HDMI2 => 1 * 2 ** 3, + Analog => 1 * 2 ** 11, + others => 0); + + procedure Initialize + is + Detected : Boolean; + hotplug_mask_set : Word32 := + CRT_HOTPLUG_INT_EN or CRT_HOTPLUG_ACTIVATION_PERIOD_64; + + To_HDMI_Port : constant array (GMCH_HDMI_Port) of Port_Type := + (DIGI_B => HDMI1, + DIGI_C => HDMI2); + To_DP_Port : constant array (GMCH_DP_Port) of Port_Type := + (DIGI_B => DP1, + DIGI_C => DP2, + DIGI_D => DP3); + + begin + for HDMI_Port in GMCH_HDMI_Port loop + Registers.Is_Set_Mask + (Register => GMCH_HDMI (HDMI_Port), + Mask => PORT_DETECTED, + Result => Detected); + Config.Valid_Port (To_HDMI_Port (HDMI_Port)) := Detected; + hotplug_mask_set := hotplug_mask_set or + (if Detected then HDMI_PORT_HOTPLUG_EN (HDMI_Port) else 0); + end loop; + for DP_Port in GMCH_DP_Port loop + Registers.Is_Set_Mask + (Register => GMCH_DP (DP_Port), + Mask => PORT_DETECTED, + Result => Detected); + Config.Valid_Port (To_DP_Port (DP_Port)) := Detected; + hotplug_mask_set := hotplug_mask_set or + (if Detected then DP_PORT_HOTPLUG_EN (DP_Port) else 0); + end loop; + Registers.Write + (Register => Registers.PORT_HOTPLUG_EN, + Value => hotplug_mask_set); + end Initialize; + + procedure Hotplug_Detect (Port : in Active_Port_Type; Detected : out Boolean) + is + Ctl32 : Word32; + begin + Registers.Read (Register => Registers.PORT_HOTPLUG_STAT, + Value => Ctl32); + Detected := (Ctl32 and HOTPLUG_INT_STATUS (Port)) /= 0; + + if Detected then + registers.Set_Mask + (Register => Registers.PORT_HOTPLUG_STAT, + Mask => HOTPLUG_INT_STATUS (Port)); + end if; + end Hotplug_Detect; + + procedure Clear_Hotplug_Detect (Port : Active_Port_Type) + is + Ignored_HPD : Boolean; + begin + pragma Warnings (GNATprove, Off, "unused assignment to ""Ignored_HPD""", + Reason => "We want to clear pending events only"); + Port_Detect.Hotplug_Detect (Port, Ignored_HPD); + pragma Warnings (GNATprove, On, "unused assignment to ""Ignored_HPD"""); + end Clear_Hotplug_Detect; + +end HW.GFX.GMA.Port_Detect; diff --git a/common/g45/hw-gfx-gma-power_and_clocks.adb b/common/g45/hw-gfx-gma-power_and_clocks.adb new file mode 100644 index 0000000000..d6ee9f92a6 --- /dev/null +++ b/common/g45/hw-gfx-gma-power_and_clocks.adb @@ -0,0 +1,50 @@ +-- +-- Copyright (C) 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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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 HW.Time; +with HW.GFX.GMA.Config; +with HW.GFX.GMA.Registers; + +package body HW.GFX.GMA.Power_And_Clocks is + + FSB_FREQ_SEL_MASK : constant := 7 * 2 ** 0; + CLKCFG_FSB_400 : constant Frequency_Type := 100_000_000; + CLKCFG_FSB_533 : constant Frequency_Type := 133_333_333; + CLKCFG_FSB_667 : constant Frequency_Type := 166_666_666; + CLKCFG_FSB_800 : constant Frequency_Type := 200_000_000; + CLKCFG_FSB_1067 : constant Frequency_Type := 266_666_666; + CLKCFG_FSB_1333 : constant Frequency_Type := 333_333_333; + + -- The Raw Freq is 1/4 of the FSB freq + procedure Initialize + is + CLK_CFG : Word32; + type Freq_Sel is new Natural range 0 .. 7; + begin + Registers.Read + (Register => Registers.GMCH_CLKCFG, + Value => CLK_CFG); + case Freq_Sel (CLK_CFG and FSB_FREQ_SEL_MASK) is + when 0 => Config.Raw_Clock := CLKCFG_FSB_1067; + when 1 => Config.Raw_Clock := CLKCFG_FSB_533; + when 2 => Config.Raw_Clock := CLKCFG_FSB_800; + when 3 => Config.Raw_Clock := CLKCFG_FSB_667; + when 4 => Config.Raw_Clock := CLKCFG_FSB_1333; + when 5 => Config.Raw_Clock := CLKCFG_FSB_400; + when 6 => Config.Raw_Clock := CLKCFG_FSB_1067; + when 7 => Config.Raw_Clock := CLKCFG_FSB_1333; + end case; + end Initialize; + +end HW.GFX.GMA.Power_And_Clocks; diff --git a/common/g45/hw-gfx-gma-power_and_clocks.ads b/common/g45/hw-gfx-gma-power_and_clocks.ads new file mode 100644 index 0000000000..8f6c13ceac --- /dev/null +++ b/common/g45/hw-gfx-gma-power_and_clocks.ads @@ -0,0 +1,30 @@ +-- +-- Copyright (C) 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; either version 2 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- + +private package HW.GFX.GMA.Power_And_Clocks is + + procedure Initialize; + + procedure Pre_All_Off is null; + + procedure Post_All_Off is null; + + procedure Power_Set_To (Configs : Pipe_Configs) is null; + + procedure Power_Up (Old_Configs, New_Configs : Pipe_Configs) is null; + + procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Pipe_Configs) + is null; + +end HW.GFX.GMA.Power_And_Clocks; diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template index 9473745dfe..1a4d12461b 100644 --- a/common/hw-gfx-gma-config.ads.template +++ b/common/hw-gfx-gma-config.ads.template @@ -56,9 +56,9 @@ is Has_DSP_Linoff : constant Boolean := CPU <= Ivybridge; Has_PF_Pipe_Select : constant Boolean := CPU in Ivybridge .. Haswell; VGA_Plane_Workaround : constant Boolean := CPU = Ivybridge; - Has_GMCH_VGACNTRL : constant Boolean := false; - Has_GMCH_DP_Transcoder : constant Boolean := false; - Has_GMCH_PFIT_CONTROL : constant Boolean := false; + Has_GMCH_DP_Transcoder : constant Boolean := CPU = G45; + Has_GMCH_VGACNTRL : constant Boolean := CPU = G45; + Has_GMCH_PFIT_CONTROL : constant Boolean := CPU = G45; ----- Panel power: ----- Has_PP_Write_Protection : constant Boolean := CPU <= Ivybridge; @@ -67,7 +67,7 @@ is Has_PCH_Panel_Power : constant Boolean := CPU >= Ironlake; ----- PCH/FDI: --------- - Has_PCH : constant Boolean := CPU /= Broxton; + Has_PCH : constant Boolean := CPU /= Broxton and CPU /= G45; Has_PCH_DAC : constant Boolean := CPU in Ironlake .. Ivybridge or (CPU in Broadwell .. Haswell and CPU_Var = Normal); @@ -87,6 +87,8 @@ is Has_FDI_RX_Power_Down : constant Boolean := CPU in Haswell .. Broadwell; + Has_GMCH_RawClk : constant Boolean := CPU = G45; + ----- DDI: ------------- End_EDP_Training_Late : constant Boolean := CPU in Haswell .. Broadwell; Has_Per_DDI_Clock_Sel : constant Boolean := CPU in Haswell .. Broadwell; @@ -142,7 +144,12 @@ is type Valid_Per_Port is array (Port_Type) of Boolean; type Valid_Per_GPU is array (CPU_Type) of Valid_Per_Port; Valid_Port_GPU : Valid_Per_GPU := - (Ironlake => + (G45 => + (Disabled => False, + Internal => Config.Internal_Display = LVDS, + HDMI3 => False, + others => True), + Ironlake => (Disabled => False, Internal => Config.Internal_Display = LVDS, others => True), @@ -230,6 +237,7 @@ is Default_CDClk_Freq : constant Frequency_Type := (case CPU is + when G45 => 320_000_000, -- unused when Ironlake | Haswell | Broadwell => 450_000_000, @@ -240,6 +248,7 @@ is Default_RawClk_Freq : constant Frequency_Type := (case CPU is + when G45 => 100_000_000, -- unused, depends on FSB when Ironlake | Sandybridge | Ivybridge => 125_000_000, @@ -263,6 +272,10 @@ is Maximum_Scalable_Width : constant Width_Per_Pipe := (case CPU is + when G45 => -- TODO: Is this true? + (Primary => 4096, + Secondary => 2048, + Tertiary => Pos16'First), when Ironlake..Haswell => (Primary => 4096, Secondary => 2048, @@ -281,25 +294,25 @@ is ---------------------------------------------------------------------------- GTT_Offset : constant := (case CPU is - when Ironlake .. Haswell => 16#0020_0000#, + when G45 .. Haswell => 16#0020_0000#, when Broadwell .. Skylake => 16#0080_0000#); GTT_Size : constant := (case CPU is - when Ironlake .. Haswell => 16#0020_0000#, + when G45 .. Haswell => 16#0020_0000#, -- Limit Broadwell to 4MiB to have a stable -- interface (i.e. same number of entries): when Broadwell .. Skylake => 16#0040_0000#); GTT_PTE_Size : constant := (case CPU is - when Ironlake .. Haswell => 4, - when Broadwell .. Skylake => 8); + when G45 .. Haswell => 4, + when Broadwell .. Skylake => 8); Fence_Base : constant := (case CPU is - when Ironlake => 16#0000_3000#, + when G45 .. Ironlake => 16#0000_3000#, when Sandybridge .. Skylake => 16#0010_0000#); Fence_Count : constant := (case CPU is - when Ironlake .. Sandybridge => 16, + when G45 .. Sandybridge => 16, when Ivybridge .. Skylake => 32); ---------------------------------------------------------------------------- @@ -318,6 +331,8 @@ is function Is_GPU (Device_Id : Word16; CPU : CPU_Type; CPU_Var : CPU_Variant) return Boolean is (case CPU is + when G45 => (Device_Id and 16#ff02#) = 16#2e02# or + (Device_Id and 16#fffe#) = 16#2a42#, when Ironlake => (Device_Id and 16#fff3#) = 16#0042#, when Sandybridge => (Device_Id and 16#ffc2#) = 16#0102#, when Ivybridge => (Device_Id and 16#ffc3#) = 16#0142#, diff --git a/common/hw-gfx-gma-config_helpers.adb b/common/hw-gfx-gma-config_helpers.adb index 5e5be5dab5..adc749cd44 100644 --- a/common/hw-gfx-gma-config_helpers.adb +++ b/common/hw-gfx-gma-config_helpers.adb @@ -30,6 +30,13 @@ is begin return (case Config.CPU is + when G45 => + (case Port is + when Internal => LVDS, + when HDMI1 | DP1 => DIGI_B, + when HDMI2 | DP2 => DIGI_C, + when HDMI3 | DP3 => DIGI_D, + when Analog => VGA), when Ironlake .. Ivybridge => -- everything but eDP through FDI/PCH (if Config.Internal_Is_EDP and then Port = Internal then DIGI_A diff --git a/common/hw-gfx-gma-dp_aux_request.adb b/common/hw-gfx-gma-dp_aux_request.adb index 97083b29d5..75a2cca52f 100644 --- a/common/hw-gfx-gma-dp_aux_request.adb +++ b/common/hw-gfx-gma-dp_aux_request.adb @@ -235,6 +235,8 @@ package body HW.GFX.GMA.DP_Aux_Request is Word32 ((Config.Default_CDClk_Freq + 1_000_000) / 2_000_000) else Word32 ((Config.Raw_Clock + 1_000_000) / 2_000_000)) + elsif Config.Has_GMCH_RawClk then + Word32 (Div_Round_Closest (Config.Raw_Clock, 2_000_000)) else 0); Busy : Boolean; diff --git a/common/hw-gfx-gma-pch.ads b/common/hw-gfx-gma-pch.ads index 619ccb65b3..106d2e8e94 100644 --- a/common/hw-gfx-gma-pch.ads +++ b/common/hw-gfx-gma-pch.ads @@ -26,13 +26,13 @@ private package HW.GFX.GMA.PCH is (case Config.CPU is when Ironlake => 30, when Sandybridge | Ivybridge => 29, - when Haswell .. Skylake => 0); + when others => 0); PCH_TRANSCODER_SELECT_MASK : constant := (case Config.CPU is when Ironlake => 1 * 2 ** 30, when Sandybridge | Ivybridge => 3 * 2 ** 29, - when Haswell .. Skylake => 0); + when others => 0); type PCH_TRANSCODER_SELECT_Array is array (FDI_Port_Type) of Word32; PCH_TRANSCODER_SELECT : constant PCH_TRANSCODER_SELECT_Array := diff --git a/common/hw-gfx-gma-registers.ads b/common/hw-gfx-gma-registers.ads index 480ee32806..da100ce2ae 100644 --- a/common/hw-gfx-gma-registers.ads +++ b/common/hw-gfx-gma-registers.ads @@ -50,9 +50,16 @@ is GMCH_GMBUS3, GMCH_GMBUS4, GMCH_GMBUS5, + GMCH_DPLL_A, + GMCH_DPLL_B, + GMCH_FPA0, + GMCH_FPA1, + GMCH_FPB0, + GMCH_FPB1, MBCTL, UCGCTL1, UCGCTL2, + GMCH_CLKCFG, VCS_RING_BUFFER_TAIL, VCS_RING_BUFFER_HEAD, VCS_RING_BUFFER_STRT, @@ -155,6 +162,11 @@ is PIPEB_LINK_M1, PIPEB_LINK_N1, FDI_TX_CTL_B, + PORT_HOTPLUG_EN, + PORT_HOTPLUG_STAT, + GMCH_SDVOB, + GMCH_SDVOC, + GMCH_LVDS, GMCH_PP_STATUS, GMCH_PP_CONTROL, GMCH_PP_ON_DELAYS, @@ -172,6 +184,7 @@ is VBLANK_C, VSYNC_C, PIPECSRC, + G4X_AUD_VID_DID, PIPE_VSYNCSHIFT_C, PIPEC_DATA_M1, PIPEC_DATA_N1, @@ -733,7 +746,12 @@ is SBI_DATA => 16#0c_6004# / Register_Width, SBI_CTL_STAT => 16#0c_6008# / Register_Width, - -- clock registers + -- GMCH clock registers + GMCH_DPLL_A => 16#00_6014# / Register_Width, + GMCH_FPA0 => 16#00_6040# / Register_Width, + GMCH_FPA1 => 16#00_6044# / Register_Width, + + -- PCH clock registers PCH_DPLL_A => 16#0c_6014# / Register_Width, PCH_PIXCLK_GATE => 16#0c_6020# / Register_Width, PCH_FPA0 => 16#0c_6040# / Register_Width, @@ -823,7 +841,12 @@ is PIPEB_DDI_FUNC_CTL => 16#06_1400# / Register_Width, PIPEB_MSA_MISC => 16#06_1410# / Register_Width, - -- clock registers + -- GMCH clock registers + GMCH_DPLL_B => 16#00_6018# / Register_Width, + GMCH_FPB0 => 16#00_6048# / Register_Width, + GMCH_FPB1 => 16#00_604c# / Register_Width, + + -- PCH clock registers PCH_DPLL_B => 16#0c_6018# / Register_Width, PCH_FPB0 => 16#0c_6048# / Register_Width, PCH_FPB1 => 16#0c_604c# / Register_Width, @@ -852,7 +875,7 @@ is SPBCNTR => 16#07_1280# / Register_Width, -- FDI and PCH transcoder control - FDI_TX_CTL_B => 16#06_1100# / Register_Width, + FDI_TX_CTL_B => 16#06_1100# / Register_Width, -- aliased by GMCH_ADPA FDI_RXB_CTL => 16#0f_100c# / Register_Width, FDI_RX_MISC_B => 16#0f_1010# / Register_Width, FDI_RXB_IIR => 16#0f_1014# / Register_Width, @@ -1015,7 +1038,7 @@ is DDI_AUX_DATA_A_5 => 16#06_4024# / Register_Width, -- aliased by DP_AUX_DATA_A_5 DDI_AUX_MUTEX_A => 16#06_402c# / Register_Width, - DDI_BUF_CTL_B => 16#06_4100# / Register_Width, + DDI_BUF_CTL_B => 16#06_4100# / Register_Width, -- aliased by GMCH_DP_B DDI_BUF_TRANS_B_S0T1 => 16#06_4e60# / Register_Width, DDI_BUF_TRANS_B_S0T2 => 16#06_4e64# / Register_Width, DDI_BUF_TRANS_B_S1T1 => 16#06_4e68# / Register_Width, @@ -1044,7 +1067,7 @@ is DDI_AUX_DATA_B_5 => 16#06_4124# / Register_Width, DDI_AUX_MUTEX_B => 16#06_412c# / Register_Width, - DDI_BUF_CTL_C => 16#06_4200# / Register_Width, + DDI_BUF_CTL_C => 16#06_4200# / Register_Width, -- aliased by GMCH_DP_C DDI_BUF_TRANS_C_S0T1 => 16#06_4ec0# / Register_Width, DDI_BUF_TRANS_C_S0T2 => 16#06_4ec4# / Register_Width, DDI_BUF_TRANS_C_S1T1 => 16#06_4ec8# / Register_Width, @@ -1073,7 +1096,7 @@ is DDI_AUX_DATA_C_5 => 16#06_4224# / Register_Width, DDI_AUX_MUTEX_C => 16#06_422c# / Register_Width, - DDI_BUF_CTL_D => 16#06_4300# / Register_Width, + DDI_BUF_CTL_D => 16#06_4300# / Register_Width, -- aliased by GMCH_DP_D DDI_BUF_TRANS_D_S0T1 => 16#06_4f20# / Register_Width, DDI_BUF_TRANS_D_S0T2 => 16#06_4f24# / Register_Width, DDI_BUF_TRANS_D_S1T1 => 16#06_4f28# / Register_Width, @@ -1303,15 +1326,24 @@ is BLC_PWM_CPU_CTL => 16#04_8254# / Register_Width, BLC_PWM_PCH_CTL2 => 16#0c_8254# / Register_Width, + -- GMCH LVDS Connector Registers + GMCH_LVDS => 16#06_1180# / Register_Width, + -- PCH LVDS Connector Registers PCH_LVDS => 16#0e_1180# / Register_Width, -- PCH ADPA Connector Registers PCH_ADPA => 16#0e_1100# / Register_Width, + -- GMCH DVOB Connector Registers + GMCH_SDVOB => 16#06_1140# / Register_Width, + -- PCH HDMIB Connector Registers PCH_HDMIB => 16#0e_1140# / Register_Width, + -- GMCH DVOC Connector Registers + GMCH_SDVOC => 16#06_1160# / Register_Width, + -- PCH HDMIC Connector Registers PCH_HDMIC => 16#0e_1150# / Register_Width, @@ -1365,6 +1397,7 @@ is -- audio VID/DID AUD_VID_DID => 16#06_5020# / Register_Width, PCH_AUD_VID_DID => 16#0e_5020# / Register_Width, + G4X_AUD_VID_DID => 16#06_2020# / Register_Width, -- interrupt registers DEISR => 16#04_4000# / Register_Width, @@ -1401,6 +1434,8 @@ is -- hotplug and initial detection HOTPLUG_CTL => 16#04_4030# / Register_Width, + PORT_HOTPLUG_EN => 16#06_1110# / Register_Width, + PORT_HOTPLUG_STAT => 16#06_1114# / Register_Width, SHOTPLUG_CTL => 16#0c_4030# / Register_Width, SFUSE_STRAP => 16#0c_2014# / Register_Width, @@ -1478,7 +1513,11 @@ is TRANS_VSYNCSHIFT_B => 16#0e_1028# / Register_Width, TRANS_VSYNCSHIFT_C => 16#0e_2028# / Register_Width, PCH_RAWCLK_FREQ => 16#0c_6204# / Register_Width, - QUIRK_C2004 => 16#0c_2004# / Register_Width); + QUIRK_C2004 => 16#0c_2004# / Register_Width, + + -- MCHBAR Mirror + + GMCH_CLKCFG => 16#01_0c00# / Register_Width); subtype Registers_Index is Registers_Invalid_Index range Registers_Invalid_Index'Succ (Invalid_Register) .. @@ -1486,6 +1525,9 @@ is -- aliased registers DP_CTL_A : constant Registers_Index := DDI_BUF_CTL_A; + GMCH_DP_B : constant Registers_Index := DDI_BUF_CTL_B; + GMCH_DP_C : constant Registers_Index := DDI_BUF_CTL_C; + GMCH_DP_D : constant Registers_Index := DDI_BUF_CTL_D; DP_AUX_CTL_A : constant Registers_Index := DDI_AUX_CTL_A; DP_AUX_DATA_A_1 : constant Registers_Index := DDI_AUX_DATA_A_1; DP_AUX_DATA_A_2 : constant Registers_Index := DDI_AUX_DATA_A_2; @@ -1493,6 +1535,9 @@ is DP_AUX_DATA_A_4 : constant Registers_Index := DDI_AUX_DATA_A_4; DP_AUX_DATA_A_5 : constant Registers_Index := DDI_AUX_DATA_A_5; ILK_DISPLAY_CHICKEN1 : constant Registers_Index := FUSE_STATUS; + GMCH_ADPA : constant Registers_Index := FDI_TX_CTL_B; + GMCH_HDMIB : constant Registers_Index := GMCH_SDVOB; + GMCH_HDMIC : constant Registers_Index := GMCH_SDVOC; --------------------------------------------------------------------------- diff --git a/common/hw-gfx-gma.adb b/common/hw-gfx-gma.adb index 809881a973..c3b2238c64 100644 --- a/common/hw-gfx-gma.adb +++ b/common/hw-gfx-gma.adb @@ -334,6 +334,8 @@ is Audio_VID_DID : Word32; begin case Config.CPU is + when G45 => + Registers.Read (Registers.G4X_AUD_VID_DID, Audio_VID_DID); when Haswell .. Skylake => Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID); when Ironlake .. Ivybridge => @@ -348,7 +350,10 @@ is when Ivybridge | Sandybridge => Audio_VID_DID = 16#8086_2806# or Audio_VID_DID = 16#8086_2805#, - when Ironlake => Audio_VID_DID = 16#0000_0000#); + when Ironlake => Audio_VID_DID = 16#0000_0000#, + when G45 => Audio_VID_DID = 16#8086_2801# or + Audio_VID_DID = 16#8086_2802# or + Audio_VID_DID = 16#8086_2803#); end Check_Platform; procedure Check_Platform_PCI (Success : out Boolean) @@ -600,13 +605,13 @@ is is GGC_Reg : constant := (case Config.CPU is - when Ironlake => 16#52#, + when G45 | Ironlake => 16#52#, when Sandybridge .. Skylake => 16#50#); GGC : Word16; begin Dev.Read16 (GGC, GGC_Reg); case Config.CPU is - when Ironlake => + when G45 | Ironlake => GTT_Size := GTT_Size_Gen4 (GGC); Stolen_Size := Stolen_Size_Gen4 (GGC); when Sandybridge .. Haswell => diff --git a/common/hw-gfx-gma.ads b/common/hw-gfx-gma.ads index c35c687a6f..fb5c7e5672 100644 --- a/common/hw-gfx-gma.ads +++ b/common/hw-gfx-gma.ads @@ -30,7 +30,8 @@ with is type CPU_Type is - (Ironlake, + (G45, + Ironlake, Sandybridge, Ivybridge, Haswell, diff --git a/configs/g45 b/configs/g45 new file mode 100644 index 0000000000..6b54563bc0 --- /dev/null +++ b/configs/g45 @@ -0,0 +1,5 @@ +CONFIG_GFX_GMA_CPU = G45 +CONFIG_GFX_GMA_CPU_VARIANT = Normal +CONFIG_GFX_GMA_INTERNAL_PORT = LVDS +CONFIG_GFX_GMA_ANALOG_I2C_PORT = PCH_DAC +CONFIG_GFX_GMA_DEFAULT_MMIO = 16\#e000_0000\#