blob: 133b40c0ab91759392c65a35ccd27995adbc4515 [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;
16
17with HW.Debug;
18with GNAT.Source_Info;
19
20with HW.GFX.GMA.Config;
21with HW.GFX.GMA.Registers;
22
23use type HW.Word8;
24use type HW.GFX.GMA.Registers.Registers_Invalid_Index;
25
26package body HW.GFX.GMA.DP_Aux_Request is
27
28 DP_AUX_CTL_SEND_BUSY : constant := 1 * 2 ** 31;
29 DP_AUX_CTL_DONE : constant := 1 * 2 ** 30;
30 DP_AUX_CTL_INTERRUPT_ON_DONE : constant := 1 * 2 ** 29;
31 DP_AUX_CTL_TIME_OUT_ERROR : constant := 1 * 2 ** 28;
32 DP_AUX_CTL_TIME_OUT_TIMER_MASK : constant := 3 * 2 ** 26;
33 DP_AUX_CTL_TIME_OUT_TIMER_400US : constant := 0 * 2 ** 26;
34 DP_AUX_CTL_TIME_OUT_TIMER_600US : constant := 1 * 2 ** 26;
35 DP_AUX_CTL_TIME_OUT_TIMER_800US : constant := 2 * 2 ** 26;
36 DP_AUX_CTL_TIME_OUT_TIMER_1600US : constant := 3 * 2 ** 26;
37 DP_AUX_CTL_RECEIVE_ERROR : constant := 1 * 2 ** 25;
38 DP_AUX_CTL_MESSAGE_SIZE_MASK : constant := 31 * 2 ** 20;
39 DP_AUX_CTL_MESSAGE_SIZE_SHIFT : constant := 2 ** 20;
40 DP_AUX_CTL_PRECHARGE_TIME_MASK : constant := 15 * 2 ** 16;
41 DP_AUX_CTL_PRECHARGE_TIME_SHIFT : constant := 2 ** 16;
42 DP_AUX_CTL_2X_BIT_CLOCK_DIV_MASK : constant := 2047 * 2 ** 0;
43 -- TODO: 2x bit clock divider should be programmed once before any training.
44
45 subtype DP_AUX_CTL_MESSAGE_SIZE_T is Natural range 1 .. 20;
46 function DP_AUX_CTL_MESSAGE_SIZE
47 (Message_Length : DP_AUX_CTL_MESSAGE_SIZE_T)
48 return Word32;
49
50 DDI_AUX_MUTEX_MUTEX_ENABLE : constant := 1 * 2 ** 31;
51 DDI_AUX_MUTEX_MUTEX_STATUS : constant := 1 * 2 ** 30;
52
53 type AUX_CH_Data_Regs is new Positive range 1 .. 5;
54
55 type AUX_CH_Data_Regs_Array is
56 array (AUX_CH_Data_Regs) of Registers.Registers_Index;
57
58 type AUX_CH_Registers is record
59 CTL : Registers.Registers_Index;
60 DATA : AUX_CH_Data_Regs_Array;
61 MUTEX : Registers.Registers_Invalid_Index;
62 end record;
63
64 type AUX_CH_Registers_Array is array (DP_Port) of AUX_CH_Registers;
65
66 AUX_CH : constant AUX_CH_Registers_Array :=
67 (if Config.Has_PCH_Aux_Channels then
68 AUX_CH_Registers_Array'
69 (DP_A => AUX_CH_Registers'
70 (CTL => Registers.DP_AUX_CTL_A,
71 DATA => AUX_CH_Data_Regs_Array'
72 (1 => Registers.DP_AUX_DATA_A_1,
73 2 => Registers.DP_AUX_DATA_A_2,
74 3 => Registers.DP_AUX_DATA_A_3,
75 4 => Registers.DP_AUX_DATA_A_4,
76 5 => Registers.DP_AUX_DATA_A_5),
77 MUTEX => Registers.Invalid_Register),
78 DP_B => AUX_CH_Registers'
79 (CTL => Registers.PCH_DP_AUX_CTL_B,
80 DATA => AUX_CH_Data_Regs_Array'
81 (1 => Registers.PCH_DP_AUX_DATA_B_1,
82 2 => Registers.PCH_DP_AUX_DATA_B_2,
83 3 => Registers.PCH_DP_AUX_DATA_B_3,
84 4 => Registers.PCH_DP_AUX_DATA_B_4,
85 5 => Registers.PCH_DP_AUX_DATA_B_5),
86 MUTEX => Registers.Invalid_Register),
87 DP_C => AUX_CH_Registers'
88 (CTL => Registers.PCH_DP_AUX_CTL_C,
89 DATA => AUX_CH_Data_Regs_Array'
90 (1 => Registers.PCH_DP_AUX_DATA_C_1,
91 2 => Registers.PCH_DP_AUX_DATA_C_2,
92 3 => Registers.PCH_DP_AUX_DATA_C_3,
93 4 => Registers.PCH_DP_AUX_DATA_C_4,
94 5 => Registers.PCH_DP_AUX_DATA_C_5),
95 MUTEX => Registers.Invalid_Register),
96 DP_D => AUX_CH_Registers'
97 (CTL => Registers.PCH_DP_AUX_CTL_D,
98 DATA => AUX_CH_Data_Regs_Array'
99 (1 => Registers.PCH_DP_AUX_DATA_D_1,
100 2 => Registers.PCH_DP_AUX_DATA_D_2,
101 3 => Registers.PCH_DP_AUX_DATA_D_3,
102 4 => Registers.PCH_DP_AUX_DATA_D_4,
103 5 => Registers.PCH_DP_AUX_DATA_D_5),
104 MUTEX => Registers.Invalid_Register))
105 else
106 AUX_CH_Registers_Array'
107 (DP_A => AUX_CH_Registers'
108 (CTL => Registers.DDI_AUX_CTL_A,
109 DATA => AUX_CH_Data_Regs_Array'
110 (1 => Registers.DDI_AUX_DATA_A_1,
111 2 => Registers.DDI_AUX_DATA_A_2,
112 3 => Registers.DDI_AUX_DATA_A_3,
113 4 => Registers.DDI_AUX_DATA_A_4,
114 5 => Registers.DDI_AUX_DATA_A_5),
115 MUTEX => Registers.DDI_AUX_MUTEX_A),
116 DP_B => AUX_CH_Registers'
117 (CTL => Registers.DDI_AUX_CTL_B,
118 DATA => AUX_CH_Data_Regs_Array'
119 (1 => Registers.DDI_AUX_DATA_B_1,
120 2 => Registers.DDI_AUX_DATA_B_2,
121 3 => Registers.DDI_AUX_DATA_B_3,
122 4 => Registers.DDI_AUX_DATA_B_4,
123 5 => Registers.DDI_AUX_DATA_B_5),
124 MUTEX => Registers.DDI_AUX_MUTEX_B),
125 DP_C => AUX_CH_Registers'
126 (CTL => Registers.DDI_AUX_CTL_C,
127 DATA => AUX_CH_Data_Regs_Array'
128 (1 => Registers.DDI_AUX_DATA_C_1,
129 2 => Registers.DDI_AUX_DATA_C_2,
130 3 => Registers.DDI_AUX_DATA_C_3,
131 4 => Registers.DDI_AUX_DATA_C_4,
132 5 => Registers.DDI_AUX_DATA_C_5),
133 MUTEX => Registers.DDI_AUX_MUTEX_C),
134 DP_D => AUX_CH_Registers'
135 (CTL => Registers.DDI_AUX_CTL_D,
136 DATA => AUX_CH_Data_Regs_Array'
137 (1 => Registers.DDI_AUX_DATA_D_1,
138 2 => Registers.DDI_AUX_DATA_D_2,
139 3 => Registers.DDI_AUX_DATA_D_3,
140 4 => Registers.DDI_AUX_DATA_D_4,
141 5 => Registers.DDI_AUX_DATA_D_5),
142 MUTEX => Registers.DDI_AUX_MUTEX_D)));
143
144 ----------------------------------------------------------------------------
145
146 function DP_AUX_CTL_MESSAGE_SIZE
147 (Message_Length : DP_AUX_CTL_MESSAGE_SIZE_T)
148 return Word32
149 is
150 begin
151 return Word32 (Message_Length) * DP_AUX_CTL_MESSAGE_SIZE_SHIFT;
152 end DP_AUX_CTL_MESSAGE_SIZE;
153
154 ----------------------------------------------------------------------------
155
156 procedure Aux_Request_Low
157 (Port : in DP_Port;
158 Request : in DP_Defs.Aux_Request;
159 Request_Length : in DP_Defs.Aux_Request_Length;
160 Response : out DP_Defs.Aux_Response;
161 Response_Length : out DP_Defs.Aux_Response_Length;
162 Success : out Boolean)
163 with
164 Global => (In_Out => Registers.Register_State,
165 Input => Time.State),
166 Depends =>
167 ((Registers.Register_State,
168 Response,
169 Response_Length,
170 Success)
171 =>
172 (Registers.Register_State,
173 Time.State,
174 Port,
175 Request,
176 Request_Length))
177 is
178 procedure Write_Data_Reg
179 (Register : in Registers.Registers_Index;
180 Buf : in DP_Defs.Aux_Request;
181 Length : in DP_Defs.Aux_Request_Length;
182 Offset : in DP_Defs.Aux_Request_Index)
183 is
184 Value : Word32;
185 Count : Natural;
186 begin
187 if Offset < Length then
188 if Length - Offset > 4 then
189 Count := 4;
190 else
191 Count := Length - Offset;
192 end if;
193
194 Value := 0;
195 for Idx in DP_Defs.Aux_Request_Index range 0 .. Count - 1 loop
196 Value := Value or
197 Shift_Left (Word32 (Buf (Offset + Idx)), (3 - Idx) * 8);
198 end loop;
199 Registers.Write (Register => Register, Value => Value);
200 end if;
201 end Write_Data_Reg;
202
203 procedure Read_Data_Reg
204 (Register : in Registers.Registers_Index;
205 Buf : in out DP_Defs.Aux_Response;
206 Length : in DP_Defs.Aux_Response_Length;
207 Offset : in DP_Defs.Aux_Response_Index)
208 is
209 Value : Word32;
210 Count : DP_Defs.Aux_Response_Length;
211 begin
212 if Offset < Length then
213 if Length - Offset > 4 then
214 Count := 4;
215 else
216 Count := Length - Offset;
217 end if;
218
219 Registers.Read (Register => Register, Value => Value);
220 for Idx in 0 .. Count - 1 loop
221 Buf (Offset + Idx) :=
222 Word8 (Shift_Right (Value, (3 - Idx) * 8) and 16#ff#);
223 end loop;
224 end if;
225 end Read_Data_Reg;
226
227 Busy : Boolean;
228 Status : Word32;
229 begin
230 Response := (others => 0); -- Don't care
231 Response_Length := DP_Defs.Aux_Response_Length'First;
232
233 if Config.Need_DP_Aux_Mutex then
234 Registers.Set_Mask
235 (Register => AUX_CH (Port).MUTEX,
236 Mask => DDI_AUX_MUTEX_MUTEX_ENABLE);
237 Registers.Wait_Set_Mask
238 (Register => AUX_CH (Port).MUTEX,
239 Mask => DDI_AUX_MUTEX_MUTEX_STATUS);
240 end if;
241
242 Registers.Is_Set_Mask
243 (Register => AUX_CH (Port).CTL,
244 Mask => DP_AUX_CTL_SEND_BUSY,
245 Result => Busy);
246 if Busy then
247 Success := False;
248 else
249 for Idx in AUX_CH_Data_Regs loop
250 Write_Data_Reg
251 (Register => AUX_CH (Port).DATA (Idx),
252 Buf => Request,
253 Length => Request_Length,
254 Offset => (Natural (Idx) - 1) * 4);
255 end loop;
256
257 Registers.Unset_And_Set_Mask
258 (Register => AUX_CH (Port).CTL,
259 Mask_Unset => DP_AUX_CTL_INTERRUPT_ON_DONE or
260 DP_AUX_CTL_TIME_OUT_TIMER_MASK or
261 DP_AUX_CTL_MESSAGE_SIZE_MASK,
262 Mask_Set => DP_AUX_CTL_SEND_BUSY or -- starts transfer
263 DP_AUX_CTL_DONE or -- clears the status
264 DP_AUX_CTL_TIME_OUT_ERROR or -- clears the status
265 DP_AUX_CTL_RECEIVE_ERROR or -- clears the status
266 DP_AUX_CTL_TIME_OUT_TIMER_600US or
267 DP_AUX_CTL_MESSAGE_SIZE (Request_Length));
268
269 Registers.Wait_Unset_Mask
270 (Register => AUX_CH (Port).CTL,
271 Mask => DP_AUX_CTL_SEND_BUSY);
272 Registers.Read (Register => AUX_CH (Port).CTL, Value => Status);
273 Success := (Status and
274 (DP_AUX_CTL_TIME_OUT_ERROR or DP_AUX_CTL_RECEIVE_ERROR))
275 = 0;
276
277 if Success then
278 Status := (Status and DP_AUX_CTL_MESSAGE_SIZE_MASK)
279 / DP_AUX_CTL_MESSAGE_SIZE_SHIFT;
280 if Natural (Status) < DP_Defs.Aux_Response_Length'First then
281 Success := False;
282 elsif Natural (Status) > DP_Defs.Aux_Response_Length'Last then
283 Response_Length := DP_Defs.Aux_Response_Length'Last;
284 else
285 Response_Length := Natural (Status);
286 end if;
287 end if;
288
289 if Success then
290 for Idx in AUX_CH_Data_Regs loop
291 Read_Data_Reg
292 (Register => AUX_CH (Port).DATA (Idx),
293 Buf => Response,
294 Length => Response_Length,
295 Offset => (Natural (Idx) - 1) * 4);
296 end loop;
297 end if;
298 end if;
299
300 if Config.Need_DP_Aux_Mutex then
301 Registers.Unset_And_Set_Mask
302 (Register => AUX_CH (Port).MUTEX,
303 Mask_Unset => DDI_AUX_MUTEX_MUTEX_ENABLE,
304 Mask_Set => DDI_AUX_MUTEX_MUTEX_STATUS); -- frees the mutex
305 end if;
306 end Aux_Request_Low;
307
308 ----------------------------------------------------------------------------
309
310 procedure Do_Aux_Request
311 (Port : in DP_Port;
312 Request : in DP_Defs.Aux_Request;
313 Request_Length : in DP_Defs.Aux_Request_Length;
314 Response : out DP_Defs.Aux_Response;
315 Response_Length : out DP_Defs.Aux_Response_Length;
316 Success : out Boolean)
317 is
318 begin
319 for Try in Positive range 1 .. 3 loop
320 Aux_Request_Low
321 (Port => Port,
322 Request => Request,
323 Request_Length => Request_Length,
324 Response => Response,
325 Response_Length => Response_Length,
326 Success => Success);
327 exit when Success;
328 end loop;
329 end Do_Aux_Request;
330
331end HW.GFX.GMA.DP_Aux_Request;