blob: 29fbaf6d936253d190abf4180dadd078d9a85785 [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
2-- Copyright (C) 2015-2016 secunet Security Networks AG
3-- Copyright (C) 2016 Nico Huber <nico.h@gmx.de>
4--
5-- This program is free software; you can redistribute it and/or modify
6-- it under the terms of the GNU General Public License as published by
Nico Huber125a29e2016-10-18 00:23:54 +02007-- the Free Software Foundation; either version 2 of the License, or
8-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02009--
10-- This program is distributed in the hope that it will be useful,
11-- but WITHOUT ANY WARRANTY; without even the implied warranty of
12-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13-- GNU General Public License for more details.
14--
15
16with HW.GFX.GMA.Config;
17with HW.GFX.GMA.DP_Info;
18with HW.GFX.GMA.Registers;
19
20with HW.Debug;
21with GNAT.Source_Info;
22
23package body HW.GFX.GMA.PCH.Transcoder is
24
25 type DPLL_SEL_Array is array (FDI_Port_Type) of Word32;
26 DPLL_SEL_TRANSCODER_x_DPLL_ENABLE : constant DPLL_SEL_Array :=
27 (FDI_A => 1 * 2 ** 3,
28 FDI_B => 1 * 2 ** 7,
29 FDI_C => 1 * 2 ** 11);
30 DPLL_SEL_TRANSCODER_x_DPLL_SEL_MASK : constant DPLL_SEL_Array :=
31 (FDI_A => 1 * 2 ** 0,
32 FDI_B => 1 * 2 ** 4,
33 FDI_C => 1 * 2 ** 8);
34 function DPLL_SEL_TRANSCODER_x_DPLL_SEL
35 (Port : FDI_Port_Type;
36 PLL : Word32)
37 return Word32
38 is
39 begin
40 return Shift_Left (PLL,
41 (case Port is
42 when FDI_A => 0,
43 when FDI_B => 4,
44 when FDI_C => 8));
45 end DPLL_SEL_TRANSCODER_x_DPLL_SEL;
46
47 TRANS_CONF_TRANSCODER_ENABLE : constant := 1 * 2 ** 31;
48 TRANS_CONF_TRANSCODER_STATE : constant := 1 * 2 ** 30;
49
50 TRANS_CHICKEN2_TIMING_OVERRIDE : constant := 1 * 2 ** 31;
51
52 TRANS_DP_CTL_OUTPUT_ENABLE : constant := 1 * 2 ** 31;
53 TRANS_DP_CTL_PORT_SELECT_MASK : constant := 3 * 2 ** 29;
54 TRANS_DP_CTL_PORT_SELECT_NONE : constant := 3 * 2 ** 29;
55 TRANS_DP_CTL_ENHANCED_FRAMING : constant := 1 * 2 ** 18;
56 TRANS_DP_CTL_VSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 4;
57 TRANS_DP_CTL_HSYNC_ACTIVE_HIGH : constant := 1 * 2 ** 3;
58
59 type TRANS_DP_CTL_PORT_SELECT_Array is array (PCH_Port) of Word32;
60 TRANS_DP_CTL_PORT_SELECT : constant TRANS_DP_CTL_PORT_SELECT_Array :=
61 (PCH_DP_B => 0 * 2 ** 29,
62 PCH_DP_C => 1 * 2 ** 29,
63 PCH_DP_D => 2 * 2 ** 29,
64 others => 0);
65
66 function TRANS_DP_CTL_BPC (BPC : BPC_Type) return Word32
67 is
68 begin
69 return
70 (case BPC is
71 when 6 => 2 * 2 ** 9,
72 when 10 => 1 * 2 ** 9,
73 when 12 => 3 * 2 ** 9,
74 when others => 0 * 2 ** 9);
75 end TRANS_DP_CTL_BPC;
76
77 function TRANS_DATA_M_TU (Transfer_Unit : Positive) return Word32 is
78 begin
79 return Shift_Left (Word32 (Transfer_Unit - 1), 25);
80 end TRANS_DATA_M_TU;
81
82 ----------------------------------------------------------------------------
83
84 type Transcoder_Registers is record
85 HTOTAL : Registers.Registers_Index;
86 HBLANK : Registers.Registers_Index;
87 HSYNC : Registers.Registers_Index;
88 VTOTAL : Registers.Registers_Index;
89 VBLANK : Registers.Registers_Index;
90 VSYNC : Registers.Registers_Index;
91 CONF : Registers.Registers_Index;
92 DP_CTL : Registers.Registers_Index;
93 DATA_M : Registers.Registers_Index;
94 DATA_N : Registers.Registers_Index;
95 LINK_M : Registers.Registers_Index;
96 LINK_N : Registers.Registers_Index;
97 CHICKEN2 : Registers.Registers_Index;
98 end record;
99
100 type Transcoder_Registers_Array is
101 array (FDI_Port_Type) of Transcoder_Registers;
102
103 TRANS : constant Transcoder_Registers_Array := Transcoder_Registers_Array'
104 (FDI_A =>
105 (HTOTAL => Registers.TRANS_HTOTAL_A,
106 HBLANK => Registers.TRANS_HBLANK_A,
107 HSYNC => Registers.TRANS_HSYNC_A,
108 VTOTAL => Registers.TRANS_VTOTAL_A,
109 VBLANK => Registers.TRANS_VBLANK_A,
110 VSYNC => Registers.TRANS_VSYNC_A,
111 CONF => Registers.TRANSACONF,
112 DP_CTL => Registers.TRANS_DP_CTL_A,
113 DATA_M => Registers.TRANSA_DATA_M1,
114 DATA_N => Registers.TRANSA_DATA_N1,
115 LINK_M => Registers.TRANSA_DP_LINK_M1,
116 LINK_N => Registers.TRANSA_DP_LINK_N1,
117 CHICKEN2 => Registers.TRANSA_CHICKEN2),
118 FDI_B =>
119 (HTOTAL => Registers.TRANS_HTOTAL_B,
120 HBLANK => Registers.TRANS_HBLANK_B,
121 HSYNC => Registers.TRANS_HSYNC_B,
122 VTOTAL => Registers.TRANS_VTOTAL_B,
123 VBLANK => Registers.TRANS_VBLANK_B,
124 VSYNC => Registers.TRANS_VSYNC_B,
125 CONF => Registers.TRANSBCONF,
126 DP_CTL => Registers.TRANS_DP_CTL_B,
127 DATA_M => Registers.TRANSB_DATA_M1,
128 DATA_N => Registers.TRANSB_DATA_N1,
129 LINK_M => Registers.TRANSB_DP_LINK_M1,
130 LINK_N => Registers.TRANSB_DP_LINK_N1,
131 CHICKEN2 => Registers.TRANSB_CHICKEN2),
132 FDI_C =>
133 (HTOTAL => Registers.TRANS_HTOTAL_C,
134 HBLANK => Registers.TRANS_HBLANK_C,
135 HSYNC => Registers.TRANS_HSYNC_C,
136 VTOTAL => Registers.TRANS_VTOTAL_C,
137 VBLANK => Registers.TRANS_VBLANK_C,
138 VSYNC => Registers.TRANS_VSYNC_C,
139 CONF => Registers.TRANSCCONF,
140 DP_CTL => Registers.TRANS_DP_CTL_C,
141 DATA_M => Registers.TRANSC_DATA_M1,
142 DATA_N => Registers.TRANSC_DATA_N1,
143 LINK_M => Registers.TRANSC_DP_LINK_M1,
144 LINK_N => Registers.TRANSC_DP_LINK_N1,
145 CHICKEN2 => Registers.TRANSC_CHICKEN2));
146
147 ----------------------------------------------------------------------------
148
149 procedure On
150 (Port_Cfg : Port_Config;
151 Port : FDI_Port_Type;
152 PLL : Word32)
153 is
154 Mode : constant Mode_Type := Port_Cfg.Mode;
155
156 function Encode (LSW, MSW : Pos16) return Word32 is
157 begin
158 return (Word32 (LSW) - 1) or ((Word32 (MSW) - 1) * 2 ** 16);
159 end Encode;
160 begin
161 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
162
163 if Config.Has_DPLL_SEL then
164 Registers.Unset_And_Set_Mask
165 (Register => Registers.PCH_DPLL_SEL,
166 Mask_Unset => DPLL_SEL_TRANSCODER_x_DPLL_SEL_MASK (Port),
167 Mask_Set => DPLL_SEL_TRANSCODER_x_DPLL_ENABLE (Port) or
168 DPLL_SEL_TRANSCODER_x_DPLL_SEL (Port, PLL));
169 end if;
170
171 Registers.Write
172 (Register => TRANS (Port).HTOTAL,
173 Value => Encode (Mode.H_Visible, Mode.H_Total));
174 Registers.Write
175 (Register => TRANS (Port).HBLANK,
176 Value => Encode (Mode.H_Visible, Mode.H_Total));
177 Registers.Write
178 (Register => TRANS (Port).HSYNC,
179 Value => Encode (Mode.H_Sync_Begin, Mode.H_Sync_End));
180 Registers.Write
181 (Register => TRANS (Port).VTOTAL,
182 Value => Encode (Mode.V_Visible, Mode.V_Total));
183 Registers.Write
184 (Register => TRANS (Port).VBLANK,
185 Value => Encode (Mode.V_Visible, Mode.V_Total));
186 Registers.Write
187 (Register => TRANS (Port).VSYNC,
188 Value => Encode (Mode.V_Sync_Begin, Mode.V_Sync_End));
189
190 if Port_Cfg.Display = DP then
191 declare
192 Data_M, Link_M : DP_Info.M_Type;
193 Data_N, Link_N : DP_Info.N_Type;
194 begin
195 DP_Info.Calculate_M_N
196 (Link => Port_Cfg.DP,
197 Mode => Port_Cfg.Mode,
198 Data_M => Data_M,
199 Data_N => Data_N,
200 Link_M => Link_M,
201 Link_N => Link_N);
202 Registers.Write
203 (Register => TRANS (Port).DATA_M,
204 Value => TRANS_DATA_M_TU (64) or
205 Word32 (Data_M));
206 Registers.Write
207 (Register => TRANS (Port).DATA_N,
208 Value => Word32 (Data_N));
209 Registers.Write
210 (Register => TRANS (Port).LINK_M,
211 Value => Word32 (Link_M));
212 Registers.Write
213 (Register => TRANS (Port).LINK_N,
214 Value => Word32 (Link_N));
215 end;
216
217 if Config.Has_Trans_DP_Ctl then
218 declare
219 Polarity : constant Word32 :=
220 (if Port_Cfg.Mode.H_Sync_Active_High then
221 TRANS_DP_CTL_HSYNC_ACTIVE_HIGH else 0) or
222 (if Port_Cfg.Mode.V_Sync_Active_High then
223 TRANS_DP_CTL_VSYNC_ACTIVE_HIGH else 0);
224 Enhanced_Framing : constant Word32 :=
225 (if Port_Cfg.DP.Enhanced_Framing then
226 TRANS_DP_CTL_ENHANCED_FRAMING else 0);
227 begin
228 Registers.Write
229 (Register => TRANS (Port).DP_CTL,
230 Value => TRANS_DP_CTL_OUTPUT_ENABLE or
231 TRANS_DP_CTL_PORT_SELECT (Port_Cfg.PCH_Port) or
232 Enhanced_Framing or
233 TRANS_DP_CTL_BPC (Port_Cfg.Mode.BPC) or
234 Polarity);
235 end;
236 end if;
237 end if;
238
239 if Config.Has_Trans_Timing_Ovrrde then
240 Registers.Set_Mask
241 (Register => TRANS (Port).CHICKEN2,
242 Mask => TRANS_CHICKEN2_TIMING_OVERRIDE);
243 end if;
244
245 Registers.Write
246 (Register => TRANS (Port).CONF,
247 Value => TRANS_CONF_TRANSCODER_ENABLE);
248 end On;
249
250 procedure Off (Port : FDI_Port_Type) is
251 begin
252 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
253
254 Registers.Unset_Mask
255 (Register => TRANS (Port).CONF,
256 Mask => TRANS_CONF_TRANSCODER_ENABLE);
257 Registers.Wait_Unset_Mask
258 (Register => TRANS (Port).CONF,
259 Mask => TRANS_CONF_TRANSCODER_STATE,
260 TOut_MS => 50);
261
262 if Config.Has_Trans_Timing_Ovrrde then
263 Registers.Unset_Mask
264 (Register => TRANS (Port).CHICKEN2,
265 Mask => TRANS_CHICKEN2_TIMING_OVERRIDE);
266 end if;
267
268 if Config.Has_Trans_DP_Ctl then
269 Registers.Write
270 (Register => TRANS (Port).DP_CTL,
271 Value => TRANS_DP_CTL_PORT_SELECT_NONE);
272 end if;
273
274 if Config.Has_DPLL_SEL then
275 Registers.Unset_Mask
276 (Register => Registers.PCH_DPLL_SEL,
277 Mask => DPLL_SEL_TRANSCODER_x_DPLL_ENABLE (Port));
278 end if;
279 end Off;
280
281end HW.GFX.GMA.PCH.Transcoder;