mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-17 10:31:31 +00:00
gma broxton: Implement DDI PHY power handling
DDI PHYs is a concept common to current Atom processor series. It seems the PHYs are implemented on the same die as the graphics core but still need to be configured separately. Based on the assumption that we start with disabled PHYs and it was always us if they are enabled, we only have to do a small share of what Linux' i915 does. v2: Wait for GRC done only if we want to copy its results. Change-Id: I1e59f80daa08dc64b8c3dff34202ace5dd4c5f73 Signed-off-by: Nico Huber <nico.huber@secunet.com> Reviewed-on: https://review.coreboot.org/18422 Tested-by: Nico Huber <nico.h@gmx.de> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
gfxinit-y += hw-gfx-gma-ddi_phy.adb
|
||||
gfxinit-y += hw-gfx-gma-ddi_phy.ads
|
||||
gfxinit-y += hw-gfx-gma-plls.adb
|
||||
gfxinit-y += hw-gfx-gma-plls.ads
|
||||
|
||||
262
common/broxton/hw-gfx-gma-ddi_phy.adb
Normal file
262
common/broxton/hw-gfx-gma-ddi_phy.adb
Normal file
@@ -0,0 +1,262 @@
|
||||
--
|
||||
-- Copyright (C) 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 GNAT.Source_Info;
|
||||
with HW.Debug;
|
||||
|
||||
with HW.GFX.GMA.Registers;
|
||||
|
||||
use HW.GFX.GMA.Registers;
|
||||
|
||||
package body HW.GFX.GMA.DDI_Phy is
|
||||
|
||||
subtype Dual_Channel is T range BC .. BC;
|
||||
|
||||
type DDI_Range is record
|
||||
First : DDI_Phy_Port;
|
||||
Last : DDI_Phy_Port;
|
||||
end record;
|
||||
type DDI_Range_Array is array (T) of DDI_Range;
|
||||
DDIs : constant DDI_Range_Array :=
|
||||
(A => (DIGI_A, DIGI_A),
|
||||
BC => (DIGI_B, DIGI_C));
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
type CL1CM is record
|
||||
DW0 : Registers_Index;
|
||||
DW9 : Registers_Index;
|
||||
DW10 : Registers_Index;
|
||||
DW28 : Registers_Index;
|
||||
DW30 : Registers_Index;
|
||||
end record;
|
||||
type CL1CM_Array is array (T) of CL1CM;
|
||||
PORT_CL1CM : constant CL1CM_Array :=
|
||||
(A =>
|
||||
(DW0 => BXT_PORT_CL1CM_DW0_A,
|
||||
DW9 => BXT_PORT_CL1CM_DW9_A,
|
||||
DW10 => BXT_PORT_CL1CM_DW10_A,
|
||||
DW28 => BXT_PORT_CL1CM_DW28_A,
|
||||
DW30 => BXT_PORT_CL1CM_DW30_A),
|
||||
BC =>
|
||||
(DW0 => BXT_PORT_CL1CM_DW0_BC,
|
||||
DW9 => BXT_PORT_CL1CM_DW9_BC,
|
||||
DW10 => BXT_PORT_CL1CM_DW10_BC,
|
||||
DW28 => BXT_PORT_CL1CM_DW28_BC,
|
||||
DW30 => BXT_PORT_CL1CM_DW30_BC));
|
||||
|
||||
type CL2CM is record
|
||||
DW6 : Registers_Index;
|
||||
end record;
|
||||
type CL2CM_Array is array (Dual_Channel) of CL2CM;
|
||||
PORT_CL2CM : constant CL2CM_Array :=
|
||||
(BC => (DW6 => BXT_PORT_CL2CM_DW6_BC));
|
||||
|
||||
type Port_Ref_Regs is record
|
||||
DW3 : Registers_Index;
|
||||
DW6 : Registers_Index;
|
||||
DW8 : Registers_Index;
|
||||
end record;
|
||||
type Port_Ref_Array is array (T) of Port_Ref_Regs;
|
||||
PORT_REF : constant Port_Ref_Array :=
|
||||
(A =>
|
||||
(DW3 => BXT_PORT_REF_DW3_A,
|
||||
DW6 => BXT_PORT_REF_DW6_A,
|
||||
DW8 => BXT_PORT_REF_DW8_A),
|
||||
BC =>
|
||||
(DW3 => BXT_PORT_REF_DW3_BC,
|
||||
DW6 => BXT_PORT_REF_DW6_BC,
|
||||
DW8 => BXT_PORT_REF_DW8_BC));
|
||||
|
||||
type Regs is array (T) of Registers_Index;
|
||||
PHY_CTL_FAMILY : constant Regs :=
|
||||
(A => BXT_PHY_CTL_FAM_EDP, BC => BXT_PHY_CTL_FAM_DDI);
|
||||
|
||||
type DDI_Regs is array (DDI_Phy_Port) of Registers_Index;
|
||||
PHY_CTL : constant DDI_Regs :=
|
||||
(DIGI_A => BXT_PHY_CTL_A,
|
||||
DIGI_B => BXT_PHY_CTL_B,
|
||||
DIGI_C => BXT_PHY_CTL_C);
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
type Values is array (T) of Word32;
|
||||
GT_DISPLAY_POWER_ON : constant Values :=
|
||||
(A => 1 * 2 ** 1,
|
||||
BC => 1 * 2 ** 0);
|
||||
|
||||
PORT_CL1CM_PHY_POWER_GOOD : constant := 1 * 2 ** 16;
|
||||
PORT_CL1CM_PHY_RESERVED : constant := 1 * 2 ** 7;
|
||||
|
||||
PORT_CL1CM_IREFxRC_OFFSET_SHIFT : constant := 8;
|
||||
PORT_CL1CM_IREFxRC_OFFSET_MASK : constant := 16#ff# * 2 ** 8;
|
||||
|
||||
PORT_CL1CM_OCL1_POWER_DOWN_EN : constant := 1 * 2 ** 23;
|
||||
PORT_CL1CM_OLDO_DYN_POWER_DOWN_EN : constant := 1 * 2 ** 22;
|
||||
PORT_CL1CM_SUS_CLK_CONFIG : constant := 3 * 2 ** 0;
|
||||
|
||||
PORT_CL2CM_OLDO_DYN_POWER_DOWN_EN : constant := 1 * 2 ** 28;
|
||||
|
||||
PORT_REF_GRC_DONE : constant := 1 * 2 ** 22;
|
||||
|
||||
PORT_REF_GRC_CODE_SHIFT : constant := 24;
|
||||
PORT_REF_GRC_FAST_SHIFT : constant := 16;
|
||||
PORT_REF_GRC_SLOW_SHIFT : constant := 8;
|
||||
|
||||
PORT_REF_GRC_DISABLE : constant := 1 * 2 ** 15;
|
||||
PORT_REF_GRC_READY_OVERRIDE : constant := 1 * 2 ** 1;
|
||||
|
||||
PHY_CTL_FAM_CMN_RESET_DIS : constant := 1 * 2 ** 31;
|
||||
|
||||
PHY_CTL_CMNLANE_POWERDOWN_ACK : constant := 1 * 2 ** 10;
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
procedure Is_Enabled (Phy : in T; Enabled : out Boolean)
|
||||
is
|
||||
Phy_Pwr : Word32;
|
||||
begin
|
||||
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
|
||||
|
||||
Is_Set_Mask (BXT_P_CR_GT_DISP_PWRON, GT_DISPLAY_POWER_ON (Phy), Enabled);
|
||||
|
||||
if Enabled then
|
||||
Read (PORT_CL1CM (Phy).DW0, Phy_Pwr);
|
||||
Enabled :=
|
||||
(Phy_Pwr and (PORT_CL1CM_PHY_POWER_GOOD or PORT_CL1CM_PHY_RESERVED))
|
||||
= PORT_CL1CM_PHY_POWER_GOOD;
|
||||
pragma Debug (not Enabled, Debug.Put_Line ("DDI PHY power unsettled"));
|
||||
end if;
|
||||
|
||||
if Enabled then
|
||||
Is_Set_Mask (PHY_CTL_FAMILY (Phy), PHY_CTL_FAM_CMN_RESET_DIS, Enabled);
|
||||
pragma Debug (not Enabled, Debug.Put_Line ("DDI PHY still in reset"));
|
||||
end if;
|
||||
|
||||
for DDI in DDIs (Phy).First .. DDIs (Phy).Last loop
|
||||
if Enabled then
|
||||
declare
|
||||
Common_Lane_Powerdown : Boolean;
|
||||
begin
|
||||
Is_Set_Mask
|
||||
(Register => PHY_CTL (DDI),
|
||||
Mask => PHY_CTL_CMNLANE_POWERDOWN_ACK,
|
||||
Result => Common_Lane_Powerdown);
|
||||
Enabled := not Common_Lane_Powerdown;
|
||||
pragma Debug
|
||||
(not Enabled, Debug.Put_Line ("Common lane powered down"));
|
||||
end;
|
||||
end if;
|
||||
end loop;
|
||||
end Is_Enabled;
|
||||
|
||||
procedure Power_On_Phy (Phy : T)
|
||||
with
|
||||
Pre => True
|
||||
is
|
||||
begin
|
||||
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
|
||||
|
||||
Set_Mask (BXT_P_CR_GT_DISP_PWRON, GT_DISPLAY_POWER_ON (Phy));
|
||||
|
||||
Wait
|
||||
(Register => PORT_CL1CM (Phy).DW0,
|
||||
Mask => PORT_CL1CM_PHY_POWER_GOOD or
|
||||
PORT_CL1CM_PHY_RESERVED,
|
||||
Value => PORT_CL1CM_PHY_POWER_GOOD,
|
||||
TOut_MS => 1); -- 50~100us
|
||||
|
||||
Unset_And_Set_Mask
|
||||
(Register => PORT_CL1CM (Phy).DW9,
|
||||
Mask_Unset => PORT_CL1CM_IREFxRC_OFFSET_MASK,
|
||||
Mask_Set => Shift_Left
|
||||
(16#e4#, PORT_CL1CM_IREFxRC_OFFSET_SHIFT));
|
||||
Unset_And_Set_Mask
|
||||
(Register => PORT_CL1CM (Phy).DW10,
|
||||
Mask_Unset => PORT_CL1CM_IREFxRC_OFFSET_MASK,
|
||||
Mask_Set => Shift_Left
|
||||
(16#e4#, PORT_CL1CM_IREFxRC_OFFSET_SHIFT));
|
||||
|
||||
Set_Mask
|
||||
(Register => PORT_CL1CM (Phy).DW28,
|
||||
Mask => PORT_CL1CM_OCL1_POWER_DOWN_EN or
|
||||
PORT_CL1CM_OLDO_DYN_POWER_DOWN_EN or
|
||||
PORT_CL1CM_SUS_CLK_CONFIG);
|
||||
|
||||
if Phy in Dual_Channel then
|
||||
Set_Mask (PORT_CL2CM (Phy).DW6, PORT_CL2CM_OLDO_DYN_POWER_DOWN_EN);
|
||||
end if;
|
||||
|
||||
if Phy = BC then
|
||||
declare
|
||||
GRC_Val : Word32;
|
||||
begin
|
||||
-- take RCOMP calibration result from A
|
||||
|
||||
Wait_Set_Mask (PORT_REF (A).DW3, PORT_REF_GRC_DONE, TOut_MS => 10);
|
||||
Read (PORT_REF (A).DW6, GRC_Val);
|
||||
GRC_Val := Shift_Right (GRC_Val, PORT_REF_GRC_CODE_SHIFT);
|
||||
|
||||
-- use it for BC too
|
||||
GRC_Val := Shift_Left (GRC_Val, PORT_REF_GRC_FAST_SHIFT) or
|
||||
Shift_Left (GRC_Val, PORT_REF_GRC_SLOW_SHIFT) or
|
||||
GRC_Val;
|
||||
Write (PORT_REF (Phy).DW6, GRC_Val);
|
||||
|
||||
Set_Mask
|
||||
(Register => PORT_REF (Phy).DW8,
|
||||
Mask => PORT_REF_GRC_DISABLE or
|
||||
PORT_REF_GRC_READY_OVERRIDE);
|
||||
end;
|
||||
end if;
|
||||
|
||||
Set_Mask (PHY_CTL_FAMILY (Phy), PHY_CTL_FAM_CMN_RESET_DIS);
|
||||
end Power_On_Phy;
|
||||
|
||||
procedure Power_On (Phy : T)
|
||||
is
|
||||
Phy_A_Enabled : Boolean := False;
|
||||
Enabled : Boolean;
|
||||
begin
|
||||
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
|
||||
|
||||
Is_Enabled (Phy, Enabled);
|
||||
pragma Debug (Enabled, Debug.Put_Line ("DDI PHY already enabled"));
|
||||
|
||||
if not Enabled then
|
||||
if Phy = BC then
|
||||
-- PHY BC needs RCOMP calibration results from PHY A
|
||||
Is_Enabled (A, Phy_A_Enabled);
|
||||
if not Phy_A_Enabled then
|
||||
Power_On_Phy (A);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
Power_On_Phy (Phy);
|
||||
|
||||
if Phy = BC and then not Phy_A_Enabled then
|
||||
Power_Off (A);
|
||||
end if;
|
||||
end if;
|
||||
end Power_On;
|
||||
|
||||
procedure Power_Off (Phy : T) is
|
||||
begin
|
||||
pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
|
||||
|
||||
Unset_Mask (PHY_CTL_FAMILY (Phy), PHY_CTL_FAM_CMN_RESET_DIS);
|
||||
Unset_Mask (BXT_P_CR_GT_DISP_PWRON, GT_DISPLAY_POWER_ON (Phy));
|
||||
end Power_Off;
|
||||
|
||||
end HW.GFX.GMA.DDI_Phy;
|
||||
@@ -16,7 +16,9 @@ private package HW.GFX.GMA.DDI_Phy is
|
||||
|
||||
type T is (BC, A);
|
||||
|
||||
procedure Power_On (Phy : T) is null;
|
||||
procedure Power_Off (Phy : T) is null;
|
||||
procedure Power_On (Phy : T);
|
||||
procedure Power_Off (Phy : T);
|
||||
|
||||
subtype DDI_Phy_Port is GPU_Port range DIGI_A .. DIGI_C;
|
||||
|
||||
end HW.GFX.GMA.DDI_Phy;
|
||||
|
||||
@@ -212,6 +212,11 @@ is
|
||||
DP_TP_STATUS_E,
|
||||
SRD_CTL,
|
||||
SRD_STATUS,
|
||||
BXT_PHY_CTL_A,
|
||||
BXT_PHY_CTL_B,
|
||||
BXT_PHY_CTL_C,
|
||||
BXT_PHY_CTL_FAM_EDP,
|
||||
BXT_PHY_CTL_FAM_DDI,
|
||||
AUD_VID_DID,
|
||||
PFA_WIN_POS,
|
||||
PFA_WIN_SZ,
|
||||
@@ -237,6 +242,9 @@ is
|
||||
PS_WIN_POS_1_C,
|
||||
PS_WIN_SZ_1_C,
|
||||
PS_CTRL_1_C,
|
||||
BXT_PORT_CL1CM_DW0_BC,
|
||||
BXT_PORT_CL1CM_DW9_BC,
|
||||
BXT_PORT_CL1CM_DW10_BC,
|
||||
DPLL1_CFGR1,
|
||||
DPLL1_CFGR2,
|
||||
DPLL2_CFGR1,
|
||||
@@ -246,6 +254,12 @@ is
|
||||
DPLL_CTRL1,
|
||||
DPLL_CTRL2,
|
||||
DPLL_STATUS,
|
||||
BXT_PORT_CL1CM_DW28_BC,
|
||||
BXT_PORT_CL1CM_DW30_BC,
|
||||
BXT_PORT_REF_DW3_BC,
|
||||
BXT_PORT_REF_DW6_BC,
|
||||
BXT_PORT_REF_DW8_BC,
|
||||
BXT_PORT_CL2CM_DW6_BC,
|
||||
BXT_DE_PLL_CTL,
|
||||
HTOTAL_EDP,
|
||||
HBLANK_EDP,
|
||||
@@ -457,9 +471,18 @@ is
|
||||
FDI_RXC_TUSIZE1,
|
||||
QUIRK_F2060,
|
||||
TRANSC_CHICKEN2,
|
||||
BXT_P_CR_GT_DISP_PWRON,
|
||||
GT_MAILBOX,
|
||||
GT_MAILBOX_DATA,
|
||||
GT_MAILBOX_DATA_1);
|
||||
GT_MAILBOX_DATA_1,
|
||||
BXT_PORT_CL1CM_DW0_A,
|
||||
BXT_PORT_CL1CM_DW9_A,
|
||||
BXT_PORT_CL1CM_DW10_A,
|
||||
BXT_PORT_CL1CM_DW28_A,
|
||||
BXT_PORT_CL1CM_DW30_A,
|
||||
BXT_PORT_REF_DW3_A,
|
||||
BXT_PORT_REF_DW6_A,
|
||||
BXT_PORT_REF_DW8_A);
|
||||
|
||||
pragma Warnings
|
||||
(GNATprove, Off, "pragma ""KEEP_NAMES"" ignored *(not yet supported)",
|
||||
@@ -836,6 +859,35 @@ is
|
||||
BXT_DE_PLL_CTL => 16#06_d000# / Register_Width,
|
||||
BXT_DE_PLL_ENABLE => 16#04_6070# / Register_Width,
|
||||
|
||||
-- Broxton DDI PHY registers
|
||||
BXT_P_CR_GT_DISP_PWRON => 16#13_8090# / Register_Width,
|
||||
BXT_PHY_CTL_A => 16#06_4c00# / Register_Width,
|
||||
BXT_PHY_CTL_B => 16#06_4c10# / Register_Width,
|
||||
BXT_PHY_CTL_C => 16#06_4c20# / Register_Width,
|
||||
BXT_PHY_CTL_FAM_EDP => 16#06_4c80# / Register_Width,
|
||||
BXT_PHY_CTL_FAM_DDI => 16#06_4c90# / Register_Width,
|
||||
|
||||
-- Broxton DDI PHY common lane registers
|
||||
BXT_PORT_CL1CM_DW0_A => 16#16_2000# / Register_Width,
|
||||
BXT_PORT_CL1CM_DW0_BC => 16#06_c000# / Register_Width,
|
||||
BXT_PORT_CL1CM_DW9_A => 16#16_2024# / Register_Width,
|
||||
BXT_PORT_CL1CM_DW9_BC => 16#06_c024# / Register_Width,
|
||||
BXT_PORT_CL1CM_DW10_A => 16#16_2028# / Register_Width,
|
||||
BXT_PORT_CL1CM_DW10_BC => 16#06_c028# / Register_Width,
|
||||
BXT_PORT_CL1CM_DW28_A => 16#16_2070# / Register_Width,
|
||||
BXT_PORT_CL1CM_DW28_BC => 16#06_c070# / Register_Width,
|
||||
BXT_PORT_CL1CM_DW30_A => 16#16_2078# / Register_Width,
|
||||
BXT_PORT_CL1CM_DW30_BC => 16#06_c078# / Register_Width,
|
||||
BXT_PORT_CL2CM_DW6_BC => 16#06_c358# / Register_Width,
|
||||
|
||||
-- Broxton DDI PHY ref registers
|
||||
BXT_PORT_REF_DW3_A => 16#16_218c# / Register_Width,
|
||||
BXT_PORT_REF_DW3_BC => 16#06_c18c# / Register_Width,
|
||||
BXT_PORT_REF_DW6_A => 16#16_2198# / Register_Width,
|
||||
BXT_PORT_REF_DW6_BC => 16#06_c198# / Register_Width,
|
||||
BXT_PORT_REF_DW8_A => 16#16_21a0# / Register_Width,
|
||||
BXT_PORT_REF_DW8_BC => 16#06_c1a0# / Register_Width,
|
||||
|
||||
-- Power Down Well registers
|
||||
PWR_WELL_CTL_BIOS => 16#04_5400# / Register_Width,
|
||||
PWR_WELL_CTL_DRIVER => 16#04_5404# / Register_Width,
|
||||
|
||||
Reference in New Issue
Block a user