blob: 348c3e2e98858f8f58fbba6848a3856a971ea88f [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;
Nico Huber8c45bcf2016-11-20 17:30:57 +010017
18with HW.Debug;
19
20package body HW.GFX.GMA.Config_Helpers
21is
22
23 function To_GPU_Port
24 (Pipe : Pipe_Index;
25 Port : Active_Port_Type)
26 return GPU_Port
27 is
Nico Huberad096092024-07-02 18:45:44 +020028 function Combo_PHY (Port : Port_Type) return GPU_Port is
29 (case Port is
30 when HDMI1 | DP1 => DIGI_A,
31 when HDMI2 | DP2 => DIGI_B,
32 when HDMI3 | DP3 => DIGI_C,
33 when others => LVDS); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +010034 begin
35 return
Nico Huber6621a142018-06-07 23:56:54 +020036 (case Config.Gen is
Arthur Heymans960e2392026-03-03 19:45:24 +010037 when I945 => -- LVDS, VGA, SDVO B/C on GMCH
38 (case Port is
39 when LVDS => LVDS,
40 when HDMI1 | DP1 => DIGI_B, -- SDVO B
41 when HDMI2 | DP2 => DIGI_C, -- SDVO C
42 when Analog => VGA,
43 when others => DIGI_A), -- n/a, actually
Nico Huber6621a142018-06-07 23:56:54 +020044 when G45 => -- everything on GMCH
Arthur Heymans960e2392026-03-03 19:45:24 +010045 (case Port is
46 when LVDS => LVDS,
47 when eDP => DIGI_A, -- n/a, actually
48 when HDMI1 | DP1 => DIGI_B,
49 when HDMI2 | DP2 => DIGI_C,
50 when HDMI3 | DP3 => DIGI_D,
51 when Analog => VGA,
52 when others => DIGI_A), -- n/a, actually
Nico Huber6621a142018-06-07 23:56:54 +020053 when Ironlake => -- everything but eDP through FDI/PCH
Nico Huber8beafd72020-01-07 14:59:44 +010054 (if Port = eDP then
Nico Huber8c45bcf2016-11-20 17:30:57 +010055 DIGI_A
56 else
Nico Huber6621a142018-06-07 23:56:54 +020057 (case Pipe is -- FDIs are fixed to the CPU pipe
Nico Huber8c45bcf2016-11-20 17:30:57 +010058 when Primary => DIGI_B,
59 when Secondary => DIGI_C,
60 when Tertiary => DIGI_D)),
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060061 when Tigerlake =>
Nico Huberad096092024-07-02 18:45:44 +020062 (case Port is
63 when DP_TC1 | HDMI_TC1 | USBC1 => DDI_TC1,
64 when DP_TC2 | HDMI_TC2 | USBC2 => DDI_TC2,
65 when DP_TC3 | HDMI_TC3 | USBC3 => DDI_TC3,
66 when DP_TC4 | HDMI_TC4 | USBC4 => DDI_TC4,
67 when eDP =>
68 Combo_PHY (Config.Panel_Ports (Panel_1)),
69 when others =>
70 Combo_PHY (Port)),
Nico Huber6621a142018-06-07 23:56:54 +020071 when others => -- everything but VGA directly on CPU
Nico Huber8c45bcf2016-11-20 17:30:57 +010072 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010073 when LVDS => LVDS, -- n/a, actually
74 when eDP => DIGI_A,
Nico Huber8c45bcf2016-11-20 17:30:57 +010075 when HDMI1 | DP1 => DIGI_B,
76 when HDMI2 | DP2 => DIGI_C,
77 when HDMI3 | DP3 => DIGI_D,
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060078 when Analog => DIGI_E,
79 when others => LVDS)); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +010080 end To_GPU_Port;
81
82 function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
83 is
84 begin
85 return
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060086 (if Config.Has_Type_C_Ports
87 then
Nico Huberad096092024-07-02 18:45:44 +020088 (case To_GPU_Port (Pipe_Index'First, Port) is
89 when DIGI_A => PCH_HDMI_A,
90 when DIGI_B => PCH_HDMI_B,
91 when DIGI_C => PCH_HDMI_C,
92 when DDI_TC1 => PCH_TC1,
93 when DDI_TC2 => PCH_TC2,
94 when DDI_TC3 => PCH_TC3,
95 when DDI_TC4 => PCH_TC4,
96 when DDI_TC5 => PCH_TC5,
97 when DDI_TC6 => PCH_TC6,
98 when others => PCH_LVDS) -- n/a, actually
Tim Wawrzynczak605660b2022-06-08 12:48:19 -060099 else
100 (case Port is
101 when LVDS => PCH_LVDS,
Tim Wawrzynczak605660b2022-06-08 12:48:19 -0600102 when Analog => PCH_DAC,
103 when HDMI1 => PCH_HDMI_B,
104 when HDMI2 => PCH_HDMI_C,
105 when HDMI3 => PCH_HDMI_D,
106 when DP1 => PCH_DP_B,
107 when DP2 => PCH_DP_C,
108 when DP3 => PCH_DP_D,
109 when others => PCH_LVDS)); -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +0100110 end To_PCH_Port;
111
112 function To_Display_Type (Port : Active_Port_Type) return Display_Type
113 is
114 begin
115 return Display_Type'
116 (case Port is
Nico Huberad096092024-07-02 18:45:44 +0200117 when LVDS => LVDS,
118 when eDP => DP,
119 when Analog => VGA,
120 when Physical_HDMI_Ports'Range => HDMI,
121 when Physical_DP_Ports'Range => DP,
122 when Physical_USBC_Ports'Range => DP);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100123 end To_Display_Type;
124
Nico Huber2bbd6e72020-01-07 18:22:59 +0100125 function To_Panel (Port : Active_Port_Type) return Panel_Control
126 is
127 begin
128 for P in Valid_Panels loop
129 if Port = Config.Panel_Ports (P) then
130 return P;
131 end if;
132 end loop;
133 return No_Panel;
134 end To_Panel;
135
Nico Huber88da05e2019-09-16 21:03:20 +0200136 function Highest_Dotclock (Configs : Pipe_Configs) return Frequency_Type
137 is
138 Max : Frequency_Type := Frequency_Type'First;
139 begin
140 for I in Pipe_Index loop
141 if Configs (I).Port /= Disabled and
142 Max < Configs (I).Mode.Dotclock
143 then
144 Max := Configs (I).Mode.Dotclock;
145 end if;
146 end loop;
147 return Max;
148 end Highest_Dotclock;
149
150 procedure Limit_Dotclocks
151 (Configs : in out Pipe_Configs;
152 Max : in Frequency_Type) is
153 begin
154 for I in Pipe_Index loop
155 if Configs (I).Port /= Disabled and
156 Max < Configs (I).Mode.Dotclock
157 then
158 Configs (I).Mode.Dotclock := Max;
159 end if;
160 end loop;
161 end Limit_Dotclocks;
162
Nico Huber8c45bcf2016-11-20 17:30:57 +0100163 ----------------------------------------------------------------------------
164
165 -- Prepares link rate and lane count settings for an FDI connection.
166 procedure Configure_FDI_Link
167 (Port_Cfg : in out Port_Config;
168 Success : out Boolean)
Nico Huber9a4c4c32019-09-16 22:05:11 +0200169 with
170 Post =>
171 Port_Cfg.Mode.H_Visible = Port_Cfg'Old.Mode.H_Visible and
172 Port_Cfg.Mode.V_Visible = Port_Cfg'Old.Mode.V_Visible
Nico Huber8c45bcf2016-11-20 17:30:57 +0100173 is
Nico Huber9a4c4c32019-09-16 22:05:11 +0200174 begin
175 Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
176 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
177 Config.FDI_Lane_Count (Port_Cfg.Port);
178 Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
179
Nico Huber8c45bcf2016-11-20 17:30:57 +0100180 DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
181 end Configure_FDI_Link;
182
183 -- Derives an internal port config.
184 --
185 -- This is where the magic happens that hides the hardware details
186 -- from libgfxinit's users. We have to map the pipe (Pipe_Index),
187 -- the user visible port (Port_Type) and the modeline (Mode_Type)
188 -- that we are supposed to output to an internal representation
189 -- (Port_Config) that applies to the selected hardware generation
190 -- (in GMA.Config).
191 procedure Fill_Port_Config
192 (Port_Cfg : out Port_Config;
193 Pipe : in Pipe_Index;
194 Port : in Port_Type;
195 Mode : in Mode_Type;
196 Success : out Boolean)
197 is
198 begin
199 Success :=
Nico Huberd58de7d2018-06-07 23:06:55 +0200200 (Config.Has_Tertiary_Pipe or Pipe <= Secondary) and then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100201 Config.Valid_Port (Port) and then
202 Port /= Disabled; -- Valid_Port should already cover this, but the
203 -- array is writeable, so it's hard to prove this.
204
205 if Success then
206 Port_Cfg := Port_Config'
207 (Port => To_GPU_Port (Pipe, Port),
208 PCH_Port => To_PCH_Port (Port),
209 Display => To_Display_Type (Port),
Nico Huber2bbd6e72020-01-07 18:22:59 +0100210 Panel => To_Panel (Port),
Nico Huber8c45bcf2016-11-20 17:30:57 +0100211 Mode => Mode,
212 Is_FDI => Config.Is_FDI_Port (Port),
Nico Huber7b36b692024-03-07 15:20:29 +0000213 Is_eDP => To_Display_Type (Port) = DP and
214 To_Panel (Port) /= No_Panel,
Nico Huber8c45bcf2016-11-20 17:30:57 +0100215 FDI => Default_DP,
216 DP => Default_DP);
217
Nico Huber02cfbb32017-01-09 17:41:18 +0100218 if Port_Cfg.Mode.BPC = Auto_BPC then
219 Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100220 end if;
221
Nico Huber02cfbb32017-01-09 17:41:18 +0100222 if Port_Cfg.Display = HDMI then
223 declare
224 pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
225 / Port_Cfg.Mode.BPC >= Frequency_Type'First);
226 Max_Dotclock : constant Frequency_Type :=
227 Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
228 begin
229 if Port_Cfg.Mode.Dotclock > Max_Dotclock then
230 pragma Debug (Debug.Put ("Dotclock "));
231 pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
232 pragma Debug (Debug.Put (" too high, limiting to "));
233 pragma Debug (Debug.Put_Int64 (Max_Dotclock));
234 pragma Debug (Debug.Put_Line ("."));
235 Port_Cfg.Mode.Dotclock := Max_Dotclock;
236 end if;
237 end;
238 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100239
Nico Huber02cfbb32017-01-09 17:41:18 +0100240 if Port_Cfg.Is_FDI then
241 Configure_FDI_Link (Port_Cfg, Success);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100242 end if;
243 else
244 Port_Cfg := Port_Config'
245 (Port => GPU_Port'First,
246 PCH_Port => PCH_Port'First,
247 Display => Display_Type'First,
Nico Huber2bbd6e72020-01-07 18:22:59 +0100248 Panel => No_Panel,
Nico Huber8c45bcf2016-11-20 17:30:57 +0100249 Mode => Invalid_Mode,
250 Is_FDI => False,
Nico Huber7b36b692024-03-07 15:20:29 +0000251 Is_eDP => False,
Nico Huber8c45bcf2016-11-20 17:30:57 +0100252 FDI => Default_DP,
253 DP => Default_DP);
254 end if;
255 end Fill_Port_Config;
256
257 ----------------------------------------------------------------------------
258
259 -- Validates that a given configuration should work with
260 -- a given framebuffer.
261 function Validate_Config
Nico Huberf361ec82018-06-02 18:01:45 +0200262 (FB : Framebuffer_Type;
263 Mode : Mode_Type;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200264 Pipe : Pipe_Index)
Nico Huber8c45bcf2016-11-20 17:30:57 +0100265 return Boolean
266 is
267 begin
268 -- No downscaling
269 -- Respect maximum scalable width
270 -- VGA plane is only allowed on the primary pipe
271 -- Only 32bpp RGB (ignored for VGA plane)
Nico Huber0164b022017-08-24 15:12:51 +0200272 -- Stride must be big enough and a multiple of 64 bytes or the tile size
273 -- (ignored for VGA plane)
Nico Huberab69e362018-05-29 21:20:30 +0200274 -- Y-Tiling and rotation are only supported on newer generations (with
Nico Huber9b479412017-08-27 11:55:56 +0200275 -- Plane_Control)
276 -- 90 degree rotations are only supported with Y-tiling
Nico Huber8c45bcf2016-11-20 17:30:57 +0100277 return
Nico Hubercbbaade2018-01-02 13:59:36 +0100278 ((Rotated_Width (FB) = Mode.H_Visible and
279 Rotated_Height (FB) = Mode.V_Visible) or
Nico Huber9a4c4c32019-09-16 22:05:11 +0200280 (Rotated_Width (FB) <= Config.Maximum_Scalable_Width (Pipe) and
Nico Hubercbbaade2018-01-02 13:59:36 +0100281 Rotated_Width (FB) <= Mode.H_Visible and
282 Rotated_Height (FB) <= Mode.V_Visible)) and
Nico Huber9b479412017-08-27 11:55:56 +0200283 (FB.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary) and
284 (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
285 (FB.BPC = 8 and Valid_Stride (FB) and
286 (Config.Has_Plane_Control or
Nico Huberab69e362018-05-29 21:20:30 +0200287 (FB.Tiling /= Y_Tiled and FB.Rotation = No_Rotation)) and
Nico Huber9b479412017-08-27 11:55:56 +0200288 (FB.Tiling = Y_Tiled or not Rotation_90 (FB))));
Nico Huber8c45bcf2016-11-20 17:30:57 +0100289 end Validate_Config;
290
291end HW.GFX.GMA.Config_Helpers;