blob: 3b559684538c78fedcf47ba6c4e76cd813689af1 [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
Arthur Heymans960e2392026-03-03 19:45:24 +010032 when I945 => -- LVDS, VGA, SDVO B/C on GMCH
33 (case Port is
34 when LVDS => LVDS,
35 when HDMI1 | DP1 => DIGI_B, -- SDVO B
36 when HDMI2 | DP2 => DIGI_C, -- SDVO C
37 when Analog => VGA,
38 when others => DIGI_A), -- n/a, actually
Nico Huber6621a142018-06-07 23:56:54 +020039 when G45 => -- everything on GMCH
Arthur Heymans960e2392026-03-03 19:45:24 +010040 (case Port is
41 when LVDS => LVDS,
42 when eDP => DIGI_A, -- n/a, actually
43 when HDMI1 | DP1 => DIGI_B,
44 when HDMI2 | DP2 => DIGI_C,
45 when HDMI3 | DP3 => DIGI_D,
46 when Analog => VGA,
47 when others => DIGI_A), -- n/a, actually
Nico Huber6621a142018-06-07 23:56:54 +020048 when Ironlake => -- everything but eDP through FDI/PCH
Nico Huber8beafd72020-01-07 14:59:44 +010049 (if Port = eDP then
Nico Huber8c45bcf2016-11-20 17:30:57 +010050 DIGI_A
51 else
Nico Huber6621a142018-06-07 23:56:54 +020052 (case Pipe is -- FDIs are fixed to the CPU pipe
Nico Huber8c45bcf2016-11-20 17:30:57 +010053 when Primary => DIGI_B,
54 when Secondary => DIGI_C,
55 when Tertiary => DIGI_D)),
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060056 when Tigerlake =>
57 (case Port is
58 when eDP => DIGI_A,
59 when HDMI1 | DP1 => DIGI_A,
60 when HDMI2 | DP2 => DIGI_B,
61 when HDMI3 | DP3 => DIGI_C,
62 when USBC1_DP | USBC1_HDMI => DDI_TC1,
63 when USBC2_DP | USBC2_HDMI => DDI_TC2,
64 when USBC3_DP | USBC3_HDMI => DDI_TC3,
65 when USBC4_DP | USBC4_HDMI => DDI_TC4,
66 when USBC5_DP | USBC5_HDMI => DDI_TC5,
67 when USBC6_DP | USBC6_HDMI => DDI_TC6,
68 when others => LVDS), -- n/a, actually
Nico Huber6621a142018-06-07 23:56:54 +020069 when others => -- everything but VGA directly on CPU
Nico Huber8c45bcf2016-11-20 17:30:57 +010070 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010071 when LVDS => LVDS, -- n/a, actually
72 when eDP => DIGI_A,
Nico Huber8c45bcf2016-11-20 17:30:57 +010073 when HDMI1 | DP1 => DIGI_B,
74 when HDMI2 | DP2 => DIGI_C,
75 when HDMI3 | DP3 => DIGI_D,
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060076 when Analog => DIGI_E,
77 when others => LVDS)); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +010078 end To_GPU_Port;
79
80 function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
81 is
82 begin
83 return
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060084 (if Config.Has_Type_C_Ports
85 then
86 (case Port is
87 when HDMI1 => PCH_HDMI_A,
88 when HDMI2 => PCH_HDMI_B,
89 when HDMI3 => PCH_HDMI_C,
90 when USBC1_HDMI | USBC1_DP => PCH_TC1,
91 when USBC2_HDMI | USBC2_DP => PCH_TC2,
92 when USBC3_HDMI | USBC3_DP => PCH_TC3,
93 when USBC4_HDMI | USBC4_DP => PCH_TC4,
94 when USBC5_HDMI | USBC5_DP => PCH_TC5,
95 when USBC6_HDMI | USBC6_DP => PCH_TC6,
96 when others => PCH_LVDS) -- n/a, actually
97 else
98 (case Port is
99 when LVDS => PCH_LVDS,
100 when eDP => PCH_LVDS, -- n/a, actually
101 when Analog => PCH_DAC,
102 when HDMI1 => PCH_HDMI_B,
103 when HDMI2 => PCH_HDMI_C,
104 when HDMI3 => PCH_HDMI_D,
105 when DP1 => PCH_DP_B,
106 when DP2 => PCH_DP_C,
107 when DP3 => PCH_DP_D,
108 when others => PCH_LVDS)); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +0100109 end To_PCH_Port;
110
111 function To_Display_Type (Port : Active_Port_Type) return Display_Type
112 is
113 begin
114 return Display_Type'
115 (case Port is
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600116 when LVDS => LVDS,
117 when eDP => DP,
118 when Analog => VGA,
119 when HDMI1 .. HDMI3 => HDMI,
120 when DP1 .. DP3 => DP,
121 when USBC1_DP | USBC2_DP | USBC3_DP |
122 USBC4_DP | USBC5_DP | USBC6_DP => DP,
123 when USBC1_HDMI | USBC2_HDMI | USBC3_HDMI |
124 USBC4_HDMI | USBC5_HDMI | USBC6_HDMI => HDMI);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100125 end To_Display_Type;
126
Nico Huber2bbd6e72020-01-07 18:22:59 +0100127 function To_Panel (Port : Active_Port_Type) return Panel_Control
128 is
129 begin
130 for P in Valid_Panels loop
131 if Port = Config.Panel_Ports (P) then
132 return P;
133 end if;
134 end loop;
135 return No_Panel;
136 end To_Panel;
137
Nico Huber88da05e2019-09-16 21:03:20 +0200138 function Highest_Dotclock (Configs : Pipe_Configs) return Frequency_Type
139 is
140 Max : Frequency_Type := Frequency_Type'First;
141 begin
142 for I in Pipe_Index loop
143 if Configs (I).Port /= Disabled and
144 Max < Configs (I).Mode.Dotclock
145 then
146 Max := Configs (I).Mode.Dotclock;
147 end if;
148 end loop;
149 return Max;
150 end Highest_Dotclock;
151
152 procedure Limit_Dotclocks
153 (Configs : in out Pipe_Configs;
154 Max : in Frequency_Type) is
155 begin
156 for I in Pipe_Index loop
157 if Configs (I).Port /= Disabled and
158 Max < Configs (I).Mode.Dotclock
159 then
160 Configs (I).Mode.Dotclock := Max;
161 end if;
162 end loop;
163 end Limit_Dotclocks;
164
Nico Huber8c45bcf2016-11-20 17:30:57 +0100165 ----------------------------------------------------------------------------
166
167 -- Prepares link rate and lane count settings for an FDI connection.
168 procedure Configure_FDI_Link
169 (Port_Cfg : in out Port_Config;
170 Success : out Boolean)
Nico Huber9a4c4c32019-09-16 22:05:11 +0200171 with
172 Post =>
173 Port_Cfg.Mode.H_Visible = Port_Cfg'Old.Mode.H_Visible and
174 Port_Cfg.Mode.V_Visible = Port_Cfg'Old.Mode.V_Visible
Nico Huber8c45bcf2016-11-20 17:30:57 +0100175 is
Nico Huber9a4c4c32019-09-16 22:05:11 +0200176 FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
177 Enabled : Boolean;
178 begin
179 Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
180 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
181 Config.FDI_Lane_Count (Port_Cfg.Port);
182 Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
183
184 if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100185 -- if DIGI_D enabled: (FDI names are off by one)
186 Registers.Is_Set_Mask
187 (Register => Registers.FDI_TX_CTL_C,
188 Mask => FDI_TX_CTL_FDI_TX_ENABLE,
189 Result => Enabled);
190 if Enabled then
191 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
192 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100193 end if;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200194
Nico Huber8c45bcf2016-11-20 17:30:57 +0100195 DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
196 end Configure_FDI_Link;
197
198 -- Derives an internal port config.
199 --
200 -- This is where the magic happens that hides the hardware details
201 -- from libgfxinit's users. We have to map the pipe (Pipe_Index),
202 -- the user visible port (Port_Type) and the modeline (Mode_Type)
203 -- that we are supposed to output to an internal representation
204 -- (Port_Config) that applies to the selected hardware generation
205 -- (in GMA.Config).
206 procedure Fill_Port_Config
207 (Port_Cfg : out Port_Config;
208 Pipe : in Pipe_Index;
209 Port : in Port_Type;
210 Mode : in Mode_Type;
211 Success : out Boolean)
212 is
213 begin
214 Success :=
Nico Huberd58de7d2018-06-07 23:06:55 +0200215 (Config.Has_Tertiary_Pipe or Pipe <= Secondary) and then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100216 Config.Valid_Port (Port) and then
217 Port /= Disabled; -- Valid_Port should already cover this, but the
218 -- array is writeable, so it's hard to prove this.
219
220 if Success then
221 Port_Cfg := Port_Config'
222 (Port => To_GPU_Port (Pipe, Port),
223 PCH_Port => To_PCH_Port (Port),
224 Display => To_Display_Type (Port),
Nico Huber2bbd6e72020-01-07 18:22:59 +0100225 Panel => To_Panel (Port),
Nico Huber8c45bcf2016-11-20 17:30:57 +0100226 Mode => Mode,
227 Is_FDI => Config.Is_FDI_Port (Port),
228 FDI => Default_DP,
229 DP => Default_DP);
230
Nico Huber02cfbb32017-01-09 17:41:18 +0100231 if Port_Cfg.Mode.BPC = Auto_BPC then
232 Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100233 end if;
234
Nico Huber02cfbb32017-01-09 17:41:18 +0100235 if Port_Cfg.Display = HDMI then
236 declare
237 pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
238 / Port_Cfg.Mode.BPC >= Frequency_Type'First);
239 Max_Dotclock : constant Frequency_Type :=
240 Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
241 begin
242 if Port_Cfg.Mode.Dotclock > Max_Dotclock then
243 pragma Debug (Debug.Put ("Dotclock "));
244 pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
245 pragma Debug (Debug.Put (" too high, limiting to "));
246 pragma Debug (Debug.Put_Int64 (Max_Dotclock));
247 pragma Debug (Debug.Put_Line ("."));
248 Port_Cfg.Mode.Dotclock := Max_Dotclock;
249 end if;
250 end;
251 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100252
Nico Huber02cfbb32017-01-09 17:41:18 +0100253 if Port_Cfg.Is_FDI then
254 Configure_FDI_Link (Port_Cfg, Success);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100255 end if;
256 else
257 Port_Cfg := Port_Config'
258 (Port => GPU_Port'First,
259 PCH_Port => PCH_Port'First,
260 Display => Display_Type'First,
Nico Huber2bbd6e72020-01-07 18:22:59 +0100261 Panel => No_Panel,
Nico Huber8c45bcf2016-11-20 17:30:57 +0100262 Mode => Invalid_Mode,
263 Is_FDI => False,
264 FDI => Default_DP,
265 DP => Default_DP);
266 end if;
267 end Fill_Port_Config;
268
269 ----------------------------------------------------------------------------
270
271 -- Validates that a given configuration should work with
272 -- a given framebuffer.
273 function Validate_Config
Nico Huberf361ec82018-06-02 18:01:45 +0200274 (FB : Framebuffer_Type;
275 Mode : Mode_Type;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200276 Pipe : Pipe_Index)
Nico Huber8c45bcf2016-11-20 17:30:57 +0100277 return Boolean
278 is
279 begin
280 -- No downscaling
281 -- Respect maximum scalable width
282 -- VGA plane is only allowed on the primary pipe
283 -- Only 32bpp RGB (ignored for VGA plane)
Nico Huber0164b022017-08-24 15:12:51 +0200284 -- Stride must be big enough and a multiple of 64 bytes or the tile size
285 -- (ignored for VGA plane)
Nico Huberab69e362018-05-29 21:20:30 +0200286 -- Y-Tiling and rotation are only supported on newer generations (with
Nico Huber9b479412017-08-27 11:55:56 +0200287 -- Plane_Control)
288 -- 90 degree rotations are only supported with Y-tiling
Nico Huber8c45bcf2016-11-20 17:30:57 +0100289 return
Nico Hubercbbaade2018-01-02 13:59:36 +0100290 ((Rotated_Width (FB) = Mode.H_Visible and
291 Rotated_Height (FB) = Mode.V_Visible) or
Nico Huber9a4c4c32019-09-16 22:05:11 +0200292 (Rotated_Width (FB) <= Config.Maximum_Scalable_Width (Pipe) and
Nico Hubercbbaade2018-01-02 13:59:36 +0100293 Rotated_Width (FB) <= Mode.H_Visible and
294 Rotated_Height (FB) <= Mode.V_Visible)) and
Nico Huber9b479412017-08-27 11:55:56 +0200295 (FB.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary) and
296 (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
297 (FB.BPC = 8 and Valid_Stride (FB) and
298 (Config.Has_Plane_Control or
Nico Huberab69e362018-05-29 21:20:30 +0200299 (FB.Tiling /= Y_Tiled and FB.Rotation = No_Rotation)) and
Nico Huber9b479412017-08-27 11:55:56 +0200300 (FB.Tiling = Y_Tiled or not Rotation_90 (FB))));
Nico Huber8c45bcf2016-11-20 17:30:57 +0100301 end Validate_Config;
302
303end HW.GFX.GMA.Config_Helpers;