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