blob: c8b1ec6bcae9ab4c9349c868e9b869131501a0b5 [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
2-- Copyright (C) 2015-2016 secunet Security Networks AG
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
Nico Huber125a29e2016-10-18 00:23:54 +02006-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02008--
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 HW.Time;
16with HW.GFX.GMA.Config;
17with HW.GFX.GMA.Registers;
18
19package body HW.GFX.GMA.PCH.FDI is
20
21 FDI_RX_CTL_FDI_RX_ENABLE : constant := 1 * 2 ** 31;
22 FDI_RX_CTL_FS_ERROR_CORRECTION_ENABLE : constant := 1 * 2 ** 27;
23 FDI_RX_CTL_FE_ERROR_CORRECTION_ENABLE : constant := 1 * 2 ** 26;
24 FDI_RX_CTL_PORT_WIDTH_SEL_SHIFT : constant := 19;
25 FDI_RX_CTL_FDI_PLL_ENABLE : constant := 1 * 2 ** 13;
26 FDI_RX_CTL_COMPOSITE_SYNC_SELECT : constant := 1 * 2 ** 11;
27 FDI_RX_CTL_FDI_AUTO_TRAIN : constant := 1 * 2 ** 10;
28 FDI_RX_CTL_ENHANCED_FRAMING_ENABLE : constant := 1 * 2 ** 6;
29 FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_MASK : constant := 1 * 2 ** 4;
30 FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_RAWCLK : constant := 0 * 2 ** 4;
31 FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_PCDCLK : constant := 1 * 2 ** 4;
32
Nico Huber63dc9192018-06-09 17:42:19 +020033 function TP_SHIFT return Natural is
34 (if Config.Has_New_FDI_Sink then 8 else 28);
Nico Huber83693c82016-10-08 22:17:55 +020035
Nico Huber63dc9192018-06-09 17:42:19 +020036 function FDI_RX_CTL_TRAINING_PATTERN_MASK
37 return Word32 is (Shift_Left (3, TP_SHIFT));
38
39 function FDI_RX_CTL_TRAINING_PATTERN (TP : Training_Pattern) return Word32 is
40 (case TP is
41 when TP_1 => Shift_Left (0, TP_SHIFT),
42 when TP_2 => Shift_Left (1, TP_SHIFT),
43 when TP_Idle => Shift_Left (2, TP_SHIFT),
44 when TP_None => Shift_Left (3, TP_SHIFT));
Nico Huber83693c82016-10-08 22:17:55 +020045
46 function FDI_RX_CTL_PORT_WIDTH_SEL (Lane_Count : DP_Lane_Count) return Word32
47 is
48 begin
49 return Shift_Left
50 (Word32 (Lane_Count_As_Integer (Lane_Count)) - 1,
51 FDI_RX_CTL_PORT_WIDTH_SEL_SHIFT);
52 end FDI_RX_CTL_PORT_WIDTH_SEL;
53
54 function FDI_RX_CTL_BPC (BPC : BPC_Type) return Word32
55 with Pre => True
56 is
57 begin
58 return
59 (case BPC is
60 when 6 => 2 * 2 ** 16,
61 when 10 => 1 * 2 ** 16,
62 when 12 => 3 * 2 ** 16,
63 when others => 0 * 2 ** 16);
64 end FDI_RX_CTL_BPC;
65
66 FDI_RX_MISC_FDI_RX_PWRDN_LANE1_SHIFT : constant := 26;
67 FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK : constant := 3 * 2 ** 26;
68 FDI_RX_MISC_FDI_RX_PWRDN_LANE0_SHIFT : constant := 24;
69 FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK : constant := 3 * 2 ** 24;
70 FDI_RX_MISC_TP1_TO_TP2_TIME_48 : constant := 2 * 2 ** 20;
71 FDI_RX_MISC_FDI_DELAY_90 : constant := 16#90# * 2 ** 0;
72
73 function FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (Value : Word32) return Word32
74 with Pre => True
75 is
76 begin
77 return Shift_Left (Value, FDI_RX_MISC_FDI_RX_PWRDN_LANE1_SHIFT);
78 end FDI_RX_MISC_FDI_RX_PWRDN_LANE1;
79
80 function FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (Value : Word32) return Word32
81 with Pre => True
82 is
83 begin
84 return Shift_Left (Value, FDI_RX_MISC_FDI_RX_PWRDN_LANE0_SHIFT);
85 end FDI_RX_MISC_FDI_RX_PWRDN_LANE0;
86
87 FDI_RX_TUSIZE_SHIFT : constant := 25;
88
89 function FDI_RX_TUSIZE (Value : Word32) return Word32 is
90 begin
91 return Shift_Left (Value - 1, FDI_RX_TUSIZE_SHIFT);
92 end FDI_RX_TUSIZE;
93
94 FDI_RX_INTERLANE_ALIGNMENT : constant := 1 * 2 ** 10;
95 FDI_RX_SYMBOL_LOCK : constant := 1 * 2 ** 9;
96 FDI_RX_BIT_LOCK : constant := 1 * 2 ** 8;
97
98 ----------------------------------------------------------------------------
99
100 type FDI_Registers is record
101 RX_CTL : Registers.Registers_Index;
102 RX_MISC : Registers.Registers_Index;
103 RX_TUSIZE : Registers.Registers_Index;
104 RX_IMR : Registers.Registers_Index;
105 RX_IIR : Registers.Registers_Index;
106 end record;
107 type FDI_Registers_Array is array (PCH.FDI_Port_Type) of FDI_Registers;
108 FDI_Regs : constant FDI_Registers_Array := FDI_Registers_Array'
109 (PCH.FDI_A => FDI_Registers'
110 (RX_CTL => Registers.FDI_RXA_CTL,
111 RX_MISC => Registers.FDI_RX_MISC_A,
112 RX_TUSIZE => Registers.FDI_RXA_TUSIZE1,
113 RX_IMR => Registers.FDI_RXA_IMR,
114 RX_IIR => Registers.FDI_RXA_IIR),
115 PCH.FDI_B => FDI_Registers'
116 (RX_CTL => Registers.FDI_RXB_CTL,
117 RX_MISC => Registers.FDI_RX_MISC_B,
118 RX_TUSIZE => Registers.FDI_RXB_TUSIZE1,
119 RX_IMR => Registers.FDI_RXB_IMR,
120 RX_IIR => Registers.FDI_RXB_IIR),
121 PCH.FDI_C => FDI_Registers'
122 (RX_CTL => Registers.FDI_RXC_CTL,
123 RX_MISC => Registers.FDI_RX_MISC_C,
124 RX_TUSIZE => Registers.FDI_RXC_TUSIZE1,
125 RX_IMR => Registers.FDI_RXC_IMR,
126 RX_IIR => Registers.FDI_RXC_IIR));
127
128 ----------------------------------------------------------------------------
129
130 procedure Pre_Train (Port : PCH.FDI_Port_Type; Port_Cfg : Port_Config)
131 is
132 Power_Down_Lane_Bits : constant Word32 :=
133 (if Config.Has_FDI_RX_Power_Down then
134 FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (2) or
135 FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (2)
136 else 0);
137 RX_CTL_Settings : constant Word32 :=
138 FDI_RX_CTL_PORT_WIDTH_SEL (Port_Cfg.FDI.Lane_Count) or
139 (if Config.Has_FDI_BPC then
140 FDI_RX_CTL_BPC (Port_Cfg.Mode.BPC) else 0) or
141 (if Config.Has_FDI_Composite_Sel then
142 FDI_RX_CTL_COMPOSITE_SYNC_SELECT else 0) or
143 (if Port_Cfg.FDI.Enhanced_Framing then
144 FDI_RX_CTL_ENHANCED_FRAMING_ENABLE else 0);
145 begin
146 -- TODO: HSW: check DISPIO_CR_TX_BMU_CR4, seems Linux doesn't know it
147
148 Registers.Write
149 (Register => FDI_Regs (Port).RX_MISC,
150 Value => Power_Down_Lane_Bits or
151 FDI_RX_MISC_TP1_TO_TP2_TIME_48 or
152 FDI_RX_MISC_FDI_DELAY_90);
153
154 Registers.Write
155 (Register => FDI_Regs (Port).RX_TUSIZE,
156 Value => FDI_RX_TUSIZE (64));
157
158 Registers.Unset_Mask
159 (Register => FDI_Regs (Port).RX_IMR,
160 Mask => FDI_RX_INTERLANE_ALIGNMENT or
161 FDI_RX_SYMBOL_LOCK or
162 FDI_RX_BIT_LOCK);
163 Registers.Posting_Read (FDI_Regs (Port).RX_IMR);
164 -- clear stale lock bits
165 Registers.Write
166 (Register => FDI_Regs (Port).RX_IIR,
167 Value => FDI_RX_INTERLANE_ALIGNMENT or
168 FDI_RX_SYMBOL_LOCK or
169 FDI_RX_BIT_LOCK);
170
171 Registers.Write
172 (Register => FDI_Regs (Port).RX_CTL,
173 Value => FDI_RX_CTL_FDI_PLL_ENABLE or
174 RX_CTL_Settings);
175 Registers.Posting_Read (FDI_Regs (Port).RX_CTL);
176 Time.U_Delay (220);
177
178 Registers.Set_Mask
179 (Register => FDI_Regs (Port).RX_CTL,
180 Mask => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_PCDCLK);
181 end Pre_Train;
182
183 procedure Train
184 (Port : in PCH.FDI_Port_Type;
185 TP : in Training_Pattern;
186 Success : out Boolean)
187 is
188 Lock_Bit : constant Word32 :=
189 (if TP = TP_1 then FDI_RX_BIT_LOCK else FDI_RX_SYMBOL_LOCK);
190
191 procedure Check_Lock (Lock_Bit : Word32)
192 is
193 begin
194 for I in 1 .. 5 loop
195 Registers.Is_Set_Mask
196 (Register => FDI_Regs (Port).RX_IIR,
197 Mask => Lock_Bit,
198 Result => Success);
199 if Success then
200 -- clear the lock bit
201 Registers.Write
202 (Register => FDI_Regs (Port).RX_IIR,
203 Value => Lock_Bit);
204 end if;
205 exit when Success;
206 Time.U_Delay (1);
207 end loop;
208 end Check_Lock;
209 begin
210 Registers.Unset_And_Set_Mask
211 (Register => FDI_Regs (Port).RX_CTL,
212 Mask_Unset => FDI_RX_CTL_TRAINING_PATTERN_MASK,
213 Mask_Set => FDI_RX_CTL_FDI_RX_ENABLE or
214 FDI_RX_CTL_TRAINING_PATTERN (TP));
215 Registers.Posting_Read (FDI_Regs (Port).RX_CTL);
216
217 if TP <= TP_2 then
218 Time.U_Delay (1);
219 if TP = TP_1 then
220 Check_Lock (FDI_RX_BIT_LOCK);
221 else
222 Check_Lock (FDI_RX_SYMBOL_LOCK);
223 if Success then
224 Check_Lock (FDI_RX_INTERLANE_ALIGNMENT);
225 end if;
226 end if;
227 else
228 Time.U_Delay (31);
229 Success := True;
230 end if;
231 end Train;
232
233 procedure Auto_Train (Port : PCH.FDI_Port_Type)
234 is
235 begin
236 Registers.Set_Mask
237 (Register => FDI_Regs (Port).RX_CTL,
238 Mask => FDI_RX_CTL_FDI_RX_ENABLE or
239 FDI_RX_CTL_FDI_AUTO_TRAIN);
240 Registers.Posting_Read (FDI_Regs (Port).RX_CTL);
241
242 if Config.Has_FDI_RX_Power_Down then
243 Time.U_Delay (30);
244 Registers.Unset_And_Set_Mask
245 (Register => FDI_Regs (Port).RX_MISC,
246 Mask_Unset => FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK or
247 FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK,
248 Mask_Set => FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (0) or
249 FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (0));
250 Registers.Posting_Read (FDI_Regs (Port).RX_MISC);
251 end if;
252
253 Time.U_Delay (5);
254 end Auto_Train;
255
256 procedure Enable_EC (Port : PCH.FDI_Port_Type)
257 is
258 begin
259 Registers.Set_Mask
260 (Register => FDI_Regs (Port).RX_CTL,
261 Mask => FDI_RX_CTL_FS_ERROR_CORRECTION_ENABLE or
262 FDI_RX_CTL_FE_ERROR_CORRECTION_ENABLE);
263 end Enable_EC;
264
265 ----------------------------------------------------------------------------
266
267 procedure Off (Port : PCH.FDI_Port_Type; OT : Off_Type)
268 is
269 begin
270 Registers.Unset_Mask
271 (Register => FDI_Regs (Port).RX_CTL,
272 Mask => FDI_RX_CTL_FDI_RX_ENABLE or
273 FDI_RX_CTL_FDI_AUTO_TRAIN);
274
275 if Config.Has_FDI_RX_Power_Down and then OT >= Lanes_Off then
276 Registers.Unset_And_Set_Mask
277 (Register => FDI_Regs (Port).RX_MISC,
278 Mask_Unset => FDI_RX_MISC_FDI_RX_PWRDN_LANE1_MASK or
279 FDI_RX_MISC_FDI_RX_PWRDN_LANE0_MASK,
280 Mask_Set => FDI_RX_MISC_FDI_RX_PWRDN_LANE1 (2) or
281 FDI_RX_MISC_FDI_RX_PWRDN_LANE0 (2));
282 Registers.Posting_Read (FDI_Regs (Port).RX_MISC);
283 end if;
284
285 if OT >= Clock_Off then
286 Registers.Unset_And_Set_Mask
287 (Register => FDI_Regs (Port).RX_CTL,
288 Mask_Unset => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_MASK,
289 Mask_Set => FDI_RX_CTL_RAWCLK_TO_PCDCLK_SEL_RAWCLK);
290
291 Registers.Unset_Mask
292 (Register => FDI_Regs (Port).RX_CTL,
293 Mask => FDI_RX_CTL_FDI_PLL_ENABLE);
294 end if;
295 end Off;
296
297end HW.GFX.GMA.PCH.FDI;