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