blob: 868d51410d2e1973c50104ccdb38532427aa8c8f [file] [log] [blame]
Nico Huber8c45bcf2016-11-20 17:30:57 +01001--
Nico Huber88da05e2019-09-16 21:03:20 +02002-- Copyright (C) 2015-2016, 2019 secunet Security Networks AG
Nico Huber8c45bcf2016-11-20 17:30:57 +01003--
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; either version 2 of the License, or
7-- (at your option) any later version.
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
Nico Huber8c45bcf2016-11-20 17:30:57 +010015with HW.GFX.GMA.Connector_Info;
16with HW.GFX.GMA.DP_Info;
17with HW.GFX.GMA.Registers;
18
19with HW.Debug;
20
21package body HW.GFX.GMA.Config_Helpers
22is
23
24 function To_GPU_Port
25 (Pipe : Pipe_Index;
26 Port : Active_Port_Type)
27 return GPU_Port
28 is
29 begin
30 return
Nico Huber6621a142018-06-07 23:56:54 +020031 (case Config.Gen is
32 when G45 => -- everything on GMCH
Arthur Heymans73ea0322018-03-28 17:17:07 +020033 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010034 when LVDS => LVDS,
35 when eDP => DIGI_A, -- n/a, actually
Arthur Heymans73ea0322018-03-28 17:17:07 +020036 when HDMI1 | DP1 => DIGI_B,
37 when HDMI2 | DP2 => DIGI_C,
38 when HDMI3 | DP3 => DIGI_D,
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060039 when Analog => VGA,
40 when others => DIGI_A), -- n/a, actually
Nico Huber6621a142018-06-07 23:56:54 +020041 when Ironlake => -- everything but eDP through FDI/PCH
Nico Huber8beafd72020-01-07 14:59:44 +010042 (if Port = eDP then
Nico Huber8c45bcf2016-11-20 17:30:57 +010043 DIGI_A
44 else
Nico Huber6621a142018-06-07 23:56:54 +020045 (case Pipe is -- FDIs are fixed to the CPU pipe
Nico Huber8c45bcf2016-11-20 17:30:57 +010046 when Primary => DIGI_B,
47 when Secondary => DIGI_C,
48 when Tertiary => DIGI_D)),
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060049 when Tigerlake =>
50 (case Port is
51 when eDP => DIGI_A,
52 when HDMI1 | DP1 => DIGI_A,
53 when HDMI2 | DP2 => DIGI_B,
54 when HDMI3 | DP3 => DIGI_C,
55 when USBC1_DP | USBC1_HDMI => DDI_TC1,
56 when USBC2_DP | USBC2_HDMI => DDI_TC2,
57 when USBC3_DP | USBC3_HDMI => DDI_TC3,
58 when USBC4_DP | USBC4_HDMI => DDI_TC4,
59 when USBC5_DP | USBC5_HDMI => DDI_TC5,
60 when USBC6_DP | USBC6_HDMI => DDI_TC6,
61 when others => LVDS), -- n/a, actually
Nico Huber6621a142018-06-07 23:56:54 +020062 when others => -- everything but VGA directly on CPU
Nico Huber8c45bcf2016-11-20 17:30:57 +010063 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010064 when LVDS => LVDS, -- n/a, actually
65 when eDP => DIGI_A,
Nico Huber8c45bcf2016-11-20 17:30:57 +010066 when HDMI1 | DP1 => DIGI_B,
67 when HDMI2 | DP2 => DIGI_C,
68 when HDMI3 | DP3 => DIGI_D,
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060069 when Analog => DIGI_E,
70 when others => LVDS)); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +010071 end To_GPU_Port;
72
73 function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
74 is
75 begin
76 return
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060077 (if Config.Has_Type_C_Ports
78 then
79 (case Port is
80 when HDMI1 => PCH_HDMI_A,
81 when HDMI2 => PCH_HDMI_B,
82 when HDMI3 => PCH_HDMI_C,
83 when USBC1_HDMI | USBC1_DP => PCH_TC1,
84 when USBC2_HDMI | USBC2_DP => PCH_TC2,
85 when USBC3_HDMI | USBC3_DP => PCH_TC3,
86 when USBC4_HDMI | USBC4_DP => PCH_TC4,
87 when USBC5_HDMI | USBC5_DP => PCH_TC5,
88 when USBC6_HDMI | USBC6_DP => PCH_TC6,
89 when others => PCH_LVDS) -- n/a, actually
90 else
91 (case Port is
92 when LVDS => PCH_LVDS,
93 when eDP => PCH_LVDS, -- n/a, actually
94 when Analog => PCH_DAC,
95 when HDMI1 => PCH_HDMI_B,
96 when HDMI2 => PCH_HDMI_C,
97 when HDMI3 => PCH_HDMI_D,
98 when DP1 => PCH_DP_B,
99 when DP2 => PCH_DP_C,
100 when DP3 => PCH_DP_D,
101 when others => PCH_LVDS)); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +0100102 end To_PCH_Port;
103
104 function To_Display_Type (Port : Active_Port_Type) return Display_Type
105 is
106 begin
107 return Display_Type'
108 (case Port is
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600109 when LVDS => LVDS,
110 when eDP => DP,
111 when Analog => VGA,
112 when HDMI1 .. HDMI3 => HDMI,
113 when DP1 .. DP3 => DP,
114 when USBC1_DP | USBC2_DP | USBC3_DP |
115 USBC4_DP | USBC5_DP | USBC6_DP => DP,
116 when USBC1_HDMI | USBC2_HDMI | USBC3_HDMI |
117 USBC4_HDMI | USBC5_HDMI | USBC6_HDMI => HDMI);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100118 end To_Display_Type;
119
Nico Huber2bbd6e72020-01-07 18:22:59 +0100120 function To_Panel (Port : Active_Port_Type) return Panel_Control
121 is
122 begin
123 for P in Valid_Panels loop
124 if Port = Config.Panel_Ports (P) then
125 return P;
126 end if;
127 end loop;
128 return No_Panel;
129 end To_Panel;
130
Nico Huber88da05e2019-09-16 21:03:20 +0200131 function Highest_Dotclock (Configs : Pipe_Configs) return Frequency_Type
132 is
133 Max : Frequency_Type := Frequency_Type'First;
134 begin
135 for I in Pipe_Index loop
136 if Configs (I).Port /= Disabled and
137 Max < Configs (I).Mode.Dotclock
138 then
139 Max := Configs (I).Mode.Dotclock;
140 end if;
141 end loop;
142 return Max;
143 end Highest_Dotclock;
144
145 procedure Limit_Dotclocks
146 (Configs : in out Pipe_Configs;
147 Max : in Frequency_Type) is
148 begin
149 for I in Pipe_Index loop
150 if Configs (I).Port /= Disabled and
151 Max < Configs (I).Mode.Dotclock
152 then
153 Configs (I).Mode.Dotclock := Max;
154 end if;
155 end loop;
156 end Limit_Dotclocks;
157
Nico Huber8c45bcf2016-11-20 17:30:57 +0100158 ----------------------------------------------------------------------------
159
160 -- Prepares link rate and lane count settings for an FDI connection.
161 procedure Configure_FDI_Link
162 (Port_Cfg : in out Port_Config;
163 Success : out Boolean)
Nico Huber9a4c4c32019-09-16 22:05:11 +0200164 with
165 Post =>
166 Port_Cfg.Mode.H_Visible = Port_Cfg'Old.Mode.H_Visible and
167 Port_Cfg.Mode.V_Visible = Port_Cfg'Old.Mode.V_Visible
Nico Huber8c45bcf2016-11-20 17:30:57 +0100168 is
Nico Huber9a4c4c32019-09-16 22:05:11 +0200169 FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
170 Enabled : Boolean;
171 begin
172 Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
173 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
174 Config.FDI_Lane_Count (Port_Cfg.Port);
175 Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
176
177 if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100178 -- if DIGI_D enabled: (FDI names are off by one)
179 Registers.Is_Set_Mask
180 (Register => Registers.FDI_TX_CTL_C,
181 Mask => FDI_TX_CTL_FDI_TX_ENABLE,
182 Result => Enabled);
183 if Enabled then
184 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
185 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100186 end if;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200187
Nico Huber8c45bcf2016-11-20 17:30:57 +0100188 DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
189 end Configure_FDI_Link;
190
191 -- Derives an internal port config.
192 --
193 -- This is where the magic happens that hides the hardware details
194 -- from libgfxinit's users. We have to map the pipe (Pipe_Index),
195 -- the user visible port (Port_Type) and the modeline (Mode_Type)
196 -- that we are supposed to output to an internal representation
197 -- (Port_Config) that applies to the selected hardware generation
198 -- (in GMA.Config).
199 procedure Fill_Port_Config
200 (Port_Cfg : out Port_Config;
201 Pipe : in Pipe_Index;
202 Port : in Port_Type;
203 Mode : in Mode_Type;
204 Success : out Boolean)
205 is
206 begin
207 Success :=
Nico Huberd58de7d2018-06-07 23:06:55 +0200208 (Config.Has_Tertiary_Pipe or Pipe <= Secondary) and then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100209 Config.Valid_Port (Port) and then
210 Port /= Disabled; -- Valid_Port should already cover this, but the
211 -- array is writeable, so it's hard to prove this.
212
213 if Success then
214 Port_Cfg := Port_Config'
215 (Port => To_GPU_Port (Pipe, Port),
216 PCH_Port => To_PCH_Port (Port),
217 Display => To_Display_Type (Port),
Nico Huber2bbd6e72020-01-07 18:22:59 +0100218 Panel => To_Panel (Port),
Nico Huber8c45bcf2016-11-20 17:30:57 +0100219 Mode => Mode,
220 Is_FDI => Config.Is_FDI_Port (Port),
221 FDI => Default_DP,
222 DP => Default_DP);
223
Nico Huber02cfbb32017-01-09 17:41:18 +0100224 if Port_Cfg.Mode.BPC = Auto_BPC then
225 Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100226 end if;
227
Nico Huber02cfbb32017-01-09 17:41:18 +0100228 if Port_Cfg.Display = HDMI then
229 declare
230 pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
231 / Port_Cfg.Mode.BPC >= Frequency_Type'First);
232 Max_Dotclock : constant Frequency_Type :=
233 Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
234 begin
235 if Port_Cfg.Mode.Dotclock > Max_Dotclock then
236 pragma Debug (Debug.Put ("Dotclock "));
237 pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
238 pragma Debug (Debug.Put (" too high, limiting to "));
239 pragma Debug (Debug.Put_Int64 (Max_Dotclock));
240 pragma Debug (Debug.Put_Line ("."));
241 Port_Cfg.Mode.Dotclock := Max_Dotclock;
242 end if;
243 end;
244 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100245
Nico Huber02cfbb32017-01-09 17:41:18 +0100246 if Port_Cfg.Is_FDI then
247 Configure_FDI_Link (Port_Cfg, Success);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100248 end if;
249 else
250 Port_Cfg := Port_Config'
251 (Port => GPU_Port'First,
252 PCH_Port => PCH_Port'First,
253 Display => Display_Type'First,
Nico Huber2bbd6e72020-01-07 18:22:59 +0100254 Panel => No_Panel,
Nico Huber8c45bcf2016-11-20 17:30:57 +0100255 Mode => Invalid_Mode,
256 Is_FDI => False,
257 FDI => Default_DP,
258 DP => Default_DP);
259 end if;
260 end Fill_Port_Config;
261
262 ----------------------------------------------------------------------------
263
264 -- Validates that a given configuration should work with
265 -- a given framebuffer.
266 function Validate_Config
Nico Huberf361ec82018-06-02 18:01:45 +0200267 (FB : Framebuffer_Type;
268 Mode : Mode_Type;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200269 Pipe : Pipe_Index)
Nico Huber8c45bcf2016-11-20 17:30:57 +0100270 return Boolean
271 is
272 begin
273 -- No downscaling
274 -- Respect maximum scalable width
275 -- VGA plane is only allowed on the primary pipe
276 -- Only 32bpp RGB (ignored for VGA plane)
Nico Huber0164b022017-08-24 15:12:51 +0200277 -- Stride must be big enough and a multiple of 64 bytes or the tile size
278 -- (ignored for VGA plane)
Nico Huberab69e362018-05-29 21:20:30 +0200279 -- Y-Tiling and rotation are only supported on newer generations (with
Nico Huber9b479412017-08-27 11:55:56 +0200280 -- Plane_Control)
281 -- 90 degree rotations are only supported with Y-tiling
Nico Huber8c45bcf2016-11-20 17:30:57 +0100282 return
Nico Hubercbbaade2018-01-02 13:59:36 +0100283 ((Rotated_Width (FB) = Mode.H_Visible and
284 Rotated_Height (FB) = Mode.V_Visible) or
Nico Huber9a4c4c32019-09-16 22:05:11 +0200285 (Rotated_Width (FB) <= Config.Maximum_Scalable_Width (Pipe) and
Nico Hubercbbaade2018-01-02 13:59:36 +0100286 Rotated_Width (FB) <= Mode.H_Visible and
287 Rotated_Height (FB) <= Mode.V_Visible)) and
Nico Huber9b479412017-08-27 11:55:56 +0200288 (FB.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary) and
289 (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
290 (FB.BPC = 8 and Valid_Stride (FB) and
291 (Config.Has_Plane_Control or
Nico Huberab69e362018-05-29 21:20:30 +0200292 (FB.Tiling /= Y_Tiled and FB.Rotation = No_Rotation)) and
Nico Huber9b479412017-08-27 11:55:56 +0200293 (FB.Tiling = Y_Tiled or not Rotation_90 (FB))));
Nico Huber8c45bcf2016-11-20 17:30:57 +0100294 end Validate_Config;
295
296end HW.GFX.GMA.Config_Helpers;