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