blob: 446fa6625d438c71ade1abeeaf8a1e2ec3280a68 [file] [log] [blame]
Tim Wawrzynczakd1e74b42022-09-09 10:53:27 -06001--
2-- Copyright (C) 2022 Google, LLC
3--
4-- This program is free software; you can redistribute it and/or modify
5-- it under the terms of the GNU General Public License as published by
6-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
8--
9-- This program is distributed in the hope that it will be useful,
10-- but WITHOUT ANY WARRANTY; without even the implied warranty of
11-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12-- GNU General Public License for more details.
13--
14
15with GNAT.Source_Info;
16with HW.Debug;
17with HW.GFX.GMA.Registers;
18
19package body HW.GFX.GMA.Combo_Phy is
20
21 PORT_PCS_DW1_DCC_MODE_SELECT_MASK : constant := 3 * 2 ** 20;
22 PORT_PCS_DW1_DCC_MODE_SELECT_CONTINUOUS : constant := 3 * 2 ** 20;
23 PORT_COMP_DW0_COMP_INIT : constant := 1 * 2 ** 31;
24 ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2 : constant := 1 * 2 ** 29;
25 PORT_CL_DW5_POWER_DOWN_ENABLE : constant := 1 * 2 ** 4;
26 PHY_MISC_DE_TO_IO_COMP_PWR_DOWN : constant := 1 * 2 ** 23;
27 PORT_TX_DW8_ODCC_DIV_SEL_MASK : constant := 3 * 2 ** 29;
28 PORT_TX_DW8_ODCC_CLKSEL : constant := 1 * 2 ** 31;
29 PORT_COMP_DW8_IREFGEN : constant := 1 * 2 ** 24;
30 PORT_COMP_DW1_REF_MASK : constant := 16#ff_00ff#;
31
32 type Combo_Phy is (DDI_A, DDI_B, DDI_C);
33
34 type Phy_Regs_Record is record
35 PHY_MISC : Registers.Registers_Index;
36 PORT_CL_DW5 : Registers.Registers_Index;
37 PORT_COMP_DW0 : Registers.Registers_Index;
38 PORT_COMP_DW1 : Registers.Registers_Index;
39 PORT_COMP_DW3 : Registers.Registers_Index;
40 PORT_TX_DW8_LN0 : Registers.Registers_Index;
41 PORT_TX_DW8_GRP : Registers.Registers_Index;
42 PORT_PCS_DW1_LN0 : Registers.Registers_Index;
43 PORT_PCS_DW1_GRP : Registers.Registers_Index;
44 PORT_COMP_DW8 : Registers.Registers_Index;
45 PORT_COMP_DW9 : Registers.Registers_Index;
46 PORT_COMP_DW10 : Registers.Registers_Index;
47 end record;
48
49 type Combo_Phy_Regs is array (Combo_Phy) of Phy_Regs_Record;
50 Phy_Regs : constant Combo_Phy_Regs := Combo_Phy_Regs'
51 (DDI_A => Phy_Regs_Record'
52 (PHY_MISC => Registers.PHY_MISC_A,
53 PORT_CL_DW5 => Registers.PORT_CL_DW5_A,
54 PORT_COMP_DW0 => Registers.PORT_COMP_DW0_A,
55 PORT_COMP_DW1 => Registers.PORT_COMP_DW1_A,
56 PORT_COMP_DW3 => Registers.PORT_COMP_DW3_A,
57 PORT_TX_DW8_LN0 => Registers.PORT_TX_DW8_LN0_A,
58 PORT_TX_DW8_GRP => Registers.PORT_TX_DW8_GRP_A,
59 PORT_PCS_DW1_LN0 => Registers.PORT_PCS_DW1_LN0_A,
60 PORT_PCS_DW1_GRP => Registers.PORT_PCS_DW1_GRP_A,
61 PORT_COMP_DW8 => Registers.PORT_COMP_DW8_A,
62 PORT_COMP_DW9 => Registers.PORT_COMP_DW9_A,
63 PORT_COMP_DW10 => Registers.PORT_COMP_DW10_A),
64 DDI_B => Phy_Regs_Record'
65 (PHY_MISC => Registers.PHY_MISC_B,
66 PORT_CL_DW5 => Registers.PORT_CL_DW5_B,
67 PORT_COMP_DW0 => Registers.PORT_COMP_DW0_B,
68 PORT_COMP_DW1 => Registers.PORT_COMP_DW1_B,
69 PORT_COMP_DW3 => Registers.PORT_COMP_DW3_B,
70 PORT_TX_DW8_LN0 => Registers.PORT_TX_DW8_LN0_B,
71 PORT_TX_DW8_GRP => Registers.PORT_TX_DW8_GRP_B,
72 PORT_PCS_DW1_LN0 => Registers.PORT_PCS_DW1_LN0_B,
73 PORT_PCS_DW1_GRP => Registers.PORT_PCS_DW1_GRP_B,
74 PORT_COMP_DW8 => Registers.PORT_COMP_DW8_B,
75 PORT_COMP_DW9 => Registers.PORT_COMP_DW9_B,
76 PORT_COMP_DW10 => Registers.PORT_COMP_DW10_B),
77 DDI_C => Phy_Regs_Record'
78 (PHY_MISC => Registers.PHY_MISC_C,
79 PORT_CL_DW5 => Registers.PORT_CL_DW5_C,
80 PORT_COMP_DW0 => Registers.PORT_COMP_DW0_C,
81 PORT_COMP_DW1 => Registers.PORT_COMP_DW1_C,
82 PORT_COMP_DW3 => Registers.PORT_COMP_DW3_C,
83 PORT_TX_DW8_LN0 => Registers.PORT_TX_DW8_LN0_C,
84 PORT_TX_DW8_GRP => Registers.PORT_TX_DW8_GRP_C,
85 PORT_PCS_DW1_LN0 => Registers.PORT_PCS_DW1_LN0_C,
86 PORT_PCS_DW1_GRP => Registers.PORT_PCS_DW1_GRP_C,
87 PORT_COMP_DW8 => Registers.PORT_COMP_DW8_C,
88 PORT_COMP_DW9 => Registers.PORT_COMP_DW9_C,
89 PORT_COMP_DW10 => Registers.PORT_COMP_DW10_C));
90
91 procedure Propagate_To_Group
92 (Lane0_Register : Registers.Registers_Index;
93 Mask_Unset : Word32;
94 Mask_Set : Word32;
95 Group_Register : Registers.Registers_Index)
96 is
97 Value : Word32;
98 begin
99 -- Read from lane 0 and write to the group
100 Registers.Read (Lane0_Register, Value);
101 Value := (Value and not Mask_Unset) or Mask_Set;
102 Registers.Write (Group_Register, Value);
103 end Propagate_To_Group;
104
105 procedure Config_DCC_SusClk (Phy : Combo_Phy) is
106 begin
107 Propagate_To_Group
108 (Lane0_Register => Phy_Regs (Phy).PORT_TX_DW8_LN0,
109 Mask_Unset => PORT_TX_DW8_ODCC_DIV_SEL_MASK,
110 Mask_Set => PORT_TX_DW8_ODCC_CLKSEL or
111 ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2,
112 Group_Register => Phy_Regs (Phy).PORT_TX_DW8_GRP);
113
114 Propagate_To_Group
115 (Lane0_Register => Phy_Regs (Phy).PORT_PCS_DW1_LN0,
116 Mask_Unset => PORT_PCS_DW1_DCC_MODE_SELECT_MASK,
117 Mask_Set => PORT_PCS_DW1_DCC_MODE_SELECT_CONTINUOUS,
118 Group_Register => Phy_Regs (Phy).PORT_PCS_DW1_GRP);
119 end Config_DCC_SusClk;
120
121 procedure Config_Procmon_Reference (Phy : Combo_Phy)
122 is
123 type Procmon_Voltage is (VOLT_0_85, VOLT_0_95, VOLT_1_05);
124 type Procmon_Process is (DOT0, DOT1);
125 type Procmon_References is record
126 DW1 : Word32;
127 DW9 : Word32;
128 DW10 : Word32;
129 end record;
130
131 DOT0_VOLT_0_85 : constant Procmon_References :=
132 (DW1 => 16#0000_0000#,
133 DW9 => 16#62ab_67bb#,
134 DW10 => 16#5191_4f96#);
135 DOT0_VOLT_0_95 : constant Procmon_References :=
136 (DW1 => 16#0000_0000#,
137 DW9 => 16#86e1_72c7#,
138 DW10 => 16#77ca_5eab#);
139 DOT0_VOLT_1_05 : constant Procmon_References :=
140 (DW1 => 16#0000_0000#,
141 DW9 => 16#98fa_82dd#,
142 DW10 => 16#89e4_6dc1#);
143 DOT1_VOLT_0_95 : constant Procmon_References :=
144 (DW1 => 16#0000_0000#,
145 DW9 => 16#93f8_7fe1#,
146 DW10 => 16#8ae8_71c5#);
147 DOT1_VOLT_1_05 : constant Procmon_References :=
148 (DW1 => 16#0044_0000#,
149 DW9 => 16#9a00_ab25#,
150 DW10 => 16#8ae3_8ff1#);
151 procedure Read_DW3 (Phy : Combo_Phy; References : out Procmon_References)
152 is
153 DW3, Tmp : Word32;
154 Process : Procmon_Process;
155 Voltage : Procmon_Voltage;
156 PROCESS_MASK : constant := 7 * 2 ** 26;
157 VOLTAGE_MASK : constant := 3 * 2 ** 24;
158 begin
159 Registers.Read (Phy_Regs (Phy).PORT_COMP_DW3, DW3);
160
161 Tmp := Shift_Right (DW3 and VOLTAGE_MASK, 24);
162 case (Tmp) is
163 when 0 => Voltage := VOLT_0_85;
164 when 1 => Voltage := VOLT_0_95;
165 when 2 => Voltage := VOLT_1_05;
166 when others => Voltage := VOLT_0_85;
167 end case;
168
169 Tmp := Shift_Right (DW3 and PROCESS_MASK, 26);
170 case (Tmp) is
171 when 0 => Process := DOT0;
172 when 1 => Process := DOT1;
173 when others => Process := DOT0;
174 end case;
175
176 if Process = DOT0 then
177 case (Voltage) is
178 when VOLT_0_85 => References := DOT0_VOLT_0_85;
179 when VOLT_0_95 => References := DOT0_VOLT_0_95;
180 when VOLT_1_05 => References := DOT0_VOLT_1_05;
181 end case;
182 else
183 case (Voltage) is
184 -- [DOT1, VOLT_0_85] is actually an invalid combination
185 when VOLT_0_95 | VOLT_0_85 => References := DOT1_VOLT_0_95;
186 when VOLT_1_05 => References := DOT1_VOLT_1_05;
187 end case;
188 end if;
189 end Read_DW3;
190
191 References : Procmon_References;
192 begin
193 Read_DW3 (Phy, References);
194 Registers.Unset_And_Set_Mask (Register => Phy_Regs (Phy).PORT_COMP_DW1,
195 Mask_Unset => PORT_COMP_DW1_REF_MASK,
196 Mask_Set => References.DW1);
197 Registers.Write (Phy_Regs (Phy).PORT_COMP_DW9 , References.DW9);
198 Registers.Write (Phy_Regs (Phy).PORT_COMP_DW10, References.DW10);
199 end Config_Procmon_Reference;
200
201 function Phy_Is_Master (Phy : Combo_Phy) return Boolean is
202 begin
203 case Phy is
204 when DDI_A => return True;
205 when others => return False;
206 end case;
207 end Phy_Is_Master;
208
209 procedure Initialize
210 is
211 Was_Enabled : Boolean;
212 begin
213 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
214 -- Initialize all combo PHYs with Combo PHY DDI Buffer Combo PHY Init Sequence
215 for Phy in Combo_Phy'range loop
216 Registers.Is_Set_Mask (
217 Phy_Regs (Phy).PORT_COMP_DW0,
218 PORT_COMP_DW0_COMP_INIT,
219 Was_Enabled);
220
221 if not Was_Enabled then
222 Config_DCC_SusClk (Phy);
223
224 Registers.Unset_Mask
225 (Phy_Regs (Phy).PHY_MISC,
226 PHY_MISC_DE_TO_IO_COMP_PWR_DOWN);
227
228 Config_Procmon_Reference (Phy);
229
230 if Phy_Is_Master (Phy) then
231 Registers.Set_Mask (Register => Phy_Regs (Phy).PORT_COMP_DW8,
232 Mask => PORT_COMP_DW8_IREFGEN);
233 end if;
234
235 Registers.Set_Mask (Register => Phy_Regs (Phy).PORT_COMP_DW0,
236 Mask => PORT_COMP_DW0_COMP_INIT);
237
238 Registers.Set_Mask (Register => Phy_Regs (Phy).PORT_CL_DW5,
239 Mask => PORT_CL_DW5_POWER_DOWN_ENABLE);
240 end if;
241 end loop;
242 end Initialize;
243
244 procedure All_Off is
245 begin
246 for Phy in Combo_Phy'range loop
247 Registers.Set_Mask (Phy_Regs (Phy).PHY_MISC,
248 PHY_MISC_DE_TO_IO_COMP_PWR_DOWN);
249
250 Registers.Unset_Mask (Phy_Regs (Phy).PORT_COMP_DW0,
251 PORT_COMP_DW0_COMP_INIT);
252 end loop;
253 end All_Off;
254
255end HW.GFX.GMA.Combo_Phy;