blob: 014d1b2ef9922d819891eff0b5ece078e6c51b22 [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
Nico Huberad096092024-07-02 18:45:44 +020029 function Combo_PHY (Port : Port_Type) return GPU_Port is
30 (case Port is
31 when HDMI1 | DP1 => DIGI_A,
32 when HDMI2 | DP2 => DIGI_B,
33 when HDMI3 | DP3 => DIGI_C,
34 when others => LVDS); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +010035 begin
36 return
Nico Huber6621a142018-06-07 23:56:54 +020037 (case Config.Gen is
Arthur Heymans960e2392026-03-03 19:45:24 +010038 when I945 => -- LVDS, VGA, SDVO B/C on GMCH
39 (case Port is
40 when LVDS => LVDS,
41 when HDMI1 | DP1 => DIGI_B, -- SDVO B
42 when HDMI2 | DP2 => DIGI_C, -- SDVO C
43 when Analog => VGA,
44 when others => DIGI_A), -- n/a, actually
Nico Huber6621a142018-06-07 23:56:54 +020045 when G45 => -- everything on GMCH
Arthur Heymans960e2392026-03-03 19:45:24 +010046 (case Port is
47 when LVDS => LVDS,
48 when eDP => DIGI_A, -- n/a, actually
49 when HDMI1 | DP1 => DIGI_B,
50 when HDMI2 | DP2 => DIGI_C,
51 when HDMI3 | DP3 => DIGI_D,
52 when Analog => VGA,
53 when others => DIGI_A), -- n/a, actually
Nico Huber6621a142018-06-07 23:56:54 +020054 when Ironlake => -- everything but eDP through FDI/PCH
Nico Huber8beafd72020-01-07 14:59:44 +010055 (if Port = eDP then
Nico Huber8c45bcf2016-11-20 17:30:57 +010056 DIGI_A
57 else
Nico Huber6621a142018-06-07 23:56:54 +020058 (case Pipe is -- FDIs are fixed to the CPU pipe
Nico Huber8c45bcf2016-11-20 17:30:57 +010059 when Primary => DIGI_B,
60 when Secondary => DIGI_C,
61 when Tertiary => DIGI_D)),
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060062 when Tigerlake =>
Nico Huberad096092024-07-02 18:45:44 +020063 (case Port is
64 when DP_TC1 | HDMI_TC1 | USBC1 => DDI_TC1,
65 when DP_TC2 | HDMI_TC2 | USBC2 => DDI_TC2,
66 when DP_TC3 | HDMI_TC3 | USBC3 => DDI_TC3,
67 when DP_TC4 | HDMI_TC4 | USBC4 => DDI_TC4,
68 when eDP =>
69 Combo_PHY (Config.Panel_Ports (Panel_1)),
70 when others =>
71 Combo_PHY (Port)),
Nico Huber6621a142018-06-07 23:56:54 +020072 when others => -- everything but VGA directly on CPU
Nico Huber8c45bcf2016-11-20 17:30:57 +010073 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010074 when LVDS => LVDS, -- n/a, actually
75 when eDP => DIGI_A,
Nico Huber8c45bcf2016-11-20 17:30:57 +010076 when HDMI1 | DP1 => DIGI_B,
77 when HDMI2 | DP2 => DIGI_C,
78 when HDMI3 | DP3 => DIGI_D,
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060079 when Analog => DIGI_E,
80 when others => LVDS)); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +010081 end To_GPU_Port;
82
83 function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
84 is
85 begin
86 return
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060087 (if Config.Has_Type_C_Ports
88 then
Nico Huberad096092024-07-02 18:45:44 +020089 (case To_GPU_Port (Pipe_Index'First, Port) is
90 when DIGI_A => PCH_HDMI_A,
91 when DIGI_B => PCH_HDMI_B,
92 when DIGI_C => PCH_HDMI_C,
93 when DDI_TC1 => PCH_TC1,
94 when DDI_TC2 => PCH_TC2,
95 when DDI_TC3 => PCH_TC3,
96 when DDI_TC4 => PCH_TC4,
97 when DDI_TC5 => PCH_TC5,
98 when DDI_TC6 => PCH_TC6,
99 when others => PCH_LVDS) -- n/a, actually
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600100 else
101 (case Port is
102 when LVDS => PCH_LVDS,
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600103 when Analog => PCH_DAC,
104 when HDMI1 => PCH_HDMI_B,
105 when HDMI2 => PCH_HDMI_C,
106 when HDMI3 => PCH_HDMI_D,
107 when DP1 => PCH_DP_B,
108 when DP2 => PCH_DP_C,
109 when DP3 => PCH_DP_D,
110 when others => PCH_LVDS)); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +0100111 end To_PCH_Port;
112
113 function To_Display_Type (Port : Active_Port_Type) return Display_Type
114 is
115 begin
116 return Display_Type'
117 (case Port is
Nico Huberad096092024-07-02 18:45:44 +0200118 when LVDS => LVDS,
119 when eDP => DP,
120 when Analog => VGA,
121 when Physical_HDMI_Ports'Range => HDMI,
122 when Physical_DP_Ports'Range => DP,
123 when Physical_USBC_Ports'Range => DP);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100124 end To_Display_Type;
125
Nico Huber2bbd6e72020-01-07 18:22:59 +0100126 function To_Panel (Port : Active_Port_Type) return Panel_Control
127 is
128 begin
129 for P in Valid_Panels loop
130 if Port = Config.Panel_Ports (P) then
131 return P;
132 end if;
133 end loop;
134 return No_Panel;
135 end To_Panel;
136
Nico Huber88da05e2019-09-16 21:03:20 +0200137 function Highest_Dotclock (Configs : Pipe_Configs) return Frequency_Type
138 is
139 Max : Frequency_Type := Frequency_Type'First;
140 begin
141 for I in Pipe_Index loop
142 if Configs (I).Port /= Disabled and
143 Max < Configs (I).Mode.Dotclock
144 then
145 Max := Configs (I).Mode.Dotclock;
146 end if;
147 end loop;
148 return Max;
149 end Highest_Dotclock;
150
151 procedure Limit_Dotclocks
152 (Configs : in out Pipe_Configs;
153 Max : in Frequency_Type) is
154 begin
155 for I in Pipe_Index loop
156 if Configs (I).Port /= Disabled and
157 Max < Configs (I).Mode.Dotclock
158 then
159 Configs (I).Mode.Dotclock := Max;
160 end if;
161 end loop;
162 end Limit_Dotclocks;
163
Nico Huber8c45bcf2016-11-20 17:30:57 +0100164 ----------------------------------------------------------------------------
165
166 -- Prepares link rate and lane count settings for an FDI connection.
167 procedure Configure_FDI_Link
168 (Port_Cfg : in out Port_Config;
169 Success : out Boolean)
Nico Huber9a4c4c32019-09-16 22:05:11 +0200170 with
171 Post =>
172 Port_Cfg.Mode.H_Visible = Port_Cfg'Old.Mode.H_Visible and
173 Port_Cfg.Mode.V_Visible = Port_Cfg'Old.Mode.V_Visible
Nico Huber8c45bcf2016-11-20 17:30:57 +0100174 is
Nico Huber9a4c4c32019-09-16 22:05:11 +0200175 FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
176 Enabled : Boolean;
177 begin
178 Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
179 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
180 Config.FDI_Lane_Count (Port_Cfg.Port);
181 Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
182
183 if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100184 -- if DIGI_D enabled: (FDI names are off by one)
185 Registers.Is_Set_Mask
186 (Register => Registers.FDI_TX_CTL_C,
187 Mask => FDI_TX_CTL_FDI_TX_ENABLE,
188 Result => Enabled);
189 if Enabled then
190 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
191 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100192 end if;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200193
Nico Huber8c45bcf2016-11-20 17:30:57 +0100194 DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
195 end Configure_FDI_Link;
196
197 -- Derives an internal port config.
198 --
199 -- This is where the magic happens that hides the hardware details
200 -- from libgfxinit's users. We have to map the pipe (Pipe_Index),
201 -- the user visible port (Port_Type) and the modeline (Mode_Type)
202 -- that we are supposed to output to an internal representation
203 -- (Port_Config) that applies to the selected hardware generation
204 -- (in GMA.Config).
205 procedure Fill_Port_Config
206 (Port_Cfg : out Port_Config;
207 Pipe : in Pipe_Index;
208 Port : in Port_Type;
209 Mode : in Mode_Type;
210 Success : out Boolean)
211 is
212 begin
213 Success :=
Nico Huberd58de7d2018-06-07 23:06:55 +0200214 (Config.Has_Tertiary_Pipe or Pipe <= Secondary) and then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100215 Config.Valid_Port (Port) and then
216 Port /= Disabled; -- Valid_Port should already cover this, but the
217 -- array is writeable, so it's hard to prove this.
218
219 if Success then
220 Port_Cfg := Port_Config'
221 (Port => To_GPU_Port (Pipe, Port),
222 PCH_Port => To_PCH_Port (Port),
223 Display => To_Display_Type (Port),
Nico Huber2bbd6e72020-01-07 18:22:59 +0100224 Panel => To_Panel (Port),
Nico Huber8c45bcf2016-11-20 17:30:57 +0100225 Mode => Mode,
226 Is_FDI => Config.Is_FDI_Port (Port),
227 FDI => Default_DP,
228 DP => Default_DP);
229
Nico Huber02cfbb32017-01-09 17:41:18 +0100230 if Port_Cfg.Mode.BPC = Auto_BPC then
231 Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100232 end if;
233
Nico Huber02cfbb32017-01-09 17:41:18 +0100234 if Port_Cfg.Display = HDMI then
235 declare
236 pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
237 / Port_Cfg.Mode.BPC >= Frequency_Type'First);
238 Max_Dotclock : constant Frequency_Type :=
239 Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
240 begin
241 if Port_Cfg.Mode.Dotclock > Max_Dotclock then
242 pragma Debug (Debug.Put ("Dotclock "));
243 pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
244 pragma Debug (Debug.Put (" too high, limiting to "));
245 pragma Debug (Debug.Put_Int64 (Max_Dotclock));
246 pragma Debug (Debug.Put_Line ("."));
247 Port_Cfg.Mode.Dotclock := Max_Dotclock;
248 end if;
249 end;
250 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100251
Nico Huber02cfbb32017-01-09 17:41:18 +0100252 if Port_Cfg.Is_FDI then
253 Configure_FDI_Link (Port_Cfg, Success);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100254 end if;
255 else
256 Port_Cfg := Port_Config'
257 (Port => GPU_Port'First,
258 PCH_Port => PCH_Port'First,
259 Display => Display_Type'First,
Nico Huber2bbd6e72020-01-07 18:22:59 +0100260 Panel => No_Panel,
Nico Huber8c45bcf2016-11-20 17:30:57 +0100261 Mode => Invalid_Mode,
262 Is_FDI => False,
263 FDI => Default_DP,
264 DP => Default_DP);
265 end if;
266 end Fill_Port_Config;
267
268 ----------------------------------------------------------------------------
269
270 -- Validates that a given configuration should work with
271 -- a given framebuffer.
272 function Validate_Config
Nico Huberf361ec82018-06-02 18:01:45 +0200273 (FB : Framebuffer_Type;
274 Mode : Mode_Type;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200275 Pipe : Pipe_Index)
Nico Huber8c45bcf2016-11-20 17:30:57 +0100276 return Boolean
277 is
278 begin
279 -- No downscaling
280 -- Respect maximum scalable width
281 -- VGA plane is only allowed on the primary pipe
282 -- Only 32bpp RGB (ignored for VGA plane)
Nico Huber0164b022017-08-24 15:12:51 +0200283 -- Stride must be big enough and a multiple of 64 bytes or the tile size
284 -- (ignored for VGA plane)
Nico Huberab69e362018-05-29 21:20:30 +0200285 -- Y-Tiling and rotation are only supported on newer generations (with
Nico Huber9b479412017-08-27 11:55:56 +0200286 -- Plane_Control)
287 -- 90 degree rotations are only supported with Y-tiling
Nico Huber8c45bcf2016-11-20 17:30:57 +0100288 return
Nico Hubercbbaade2018-01-02 13:59:36 +0100289 ((Rotated_Width (FB) = Mode.H_Visible and
290 Rotated_Height (FB) = Mode.V_Visible) or
Nico Huber9a4c4c32019-09-16 22:05:11 +0200291 (Rotated_Width (FB) <= Config.Maximum_Scalable_Width (Pipe) and
Nico Hubercbbaade2018-01-02 13:59:36 +0100292 Rotated_Width (FB) <= Mode.H_Visible and
293 Rotated_Height (FB) <= Mode.V_Visible)) and
Nico Huber9b479412017-08-27 11:55:56 +0200294 (FB.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary) and
295 (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
296 (FB.BPC = 8 and Valid_Stride (FB) and
297 (Config.Has_Plane_Control or
Nico Huberab69e362018-05-29 21:20:30 +0200298 (FB.Tiling /= Y_Tiled and FB.Rotation = No_Rotation)) and
Nico Huber9b479412017-08-27 11:55:56 +0200299 (FB.Tiling = Y_Tiled or not Rotation_90 (FB))));
Nico Huber8c45bcf2016-11-20 17:30:57 +0100300 end Validate_Config;
301
302end HW.GFX.GMA.Config_Helpers;