blob: 2a09305b54772201558fa1fea4f7b57f4f12a6a0 [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,
39 when Analog => VGA),
Nico Huber6621a142018-06-07 23:56:54 +020040 when Ironlake => -- everything but eDP through FDI/PCH
Nico Huber8beafd72020-01-07 14:59:44 +010041 (if Port = eDP then
Nico Huber8c45bcf2016-11-20 17:30:57 +010042 DIGI_A
43 else
Nico Huber6621a142018-06-07 23:56:54 +020044 (case Pipe is -- FDIs are fixed to the CPU pipe
Nico Huber8c45bcf2016-11-20 17:30:57 +010045 when Primary => DIGI_B,
46 when Secondary => DIGI_C,
47 when Tertiary => DIGI_D)),
Nico Huber6621a142018-06-07 23:56:54 +020048 when others => -- everything but VGA directly on CPU
Nico Huber8c45bcf2016-11-20 17:30:57 +010049 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010050 when LVDS => LVDS, -- n/a, actually
51 when eDP => DIGI_A,
Nico Huber8c45bcf2016-11-20 17:30:57 +010052 when HDMI1 | DP1 => DIGI_B,
53 when HDMI2 | DP2 => DIGI_C,
54 when HDMI3 | DP3 => DIGI_D,
55 when Analog => DIGI_E));
56 end To_GPU_Port;
57
58 function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
59 is
60 begin
61 return
62 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010063 when LVDS => PCH_LVDS,
64 when eDP => PCH_LVDS, -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +010065 when Analog => PCH_DAC,
66 when HDMI1 => PCH_HDMI_B,
67 when HDMI2 => PCH_HDMI_C,
68 when HDMI3 => PCH_HDMI_D,
69 when DP1 => PCH_DP_B,
70 when DP2 => PCH_DP_C,
71 when DP3 => PCH_DP_D);
72 end To_PCH_Port;
73
74 function To_Display_Type (Port : Active_Port_Type) return Display_Type
75 is
76 begin
77 return Display_Type'
78 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010079 when LVDS => LVDS,
80 when eDP => DP,
Nico Huber8c45bcf2016-11-20 17:30:57 +010081 when Analog => VGA,
82 when HDMI1 .. HDMI3 => HDMI,
83 when DP1 .. DP3 => DP);
84 end To_Display_Type;
85
Nico Huber2bbd6e72020-01-07 18:22:59 +010086 function To_Panel (Port : Active_Port_Type) return Panel_Control
87 is
88 begin
89 for P in Valid_Panels loop
90 if Port = Config.Panel_Ports (P) then
91 return P;
92 end if;
93 end loop;
94 return No_Panel;
95 end To_Panel;
96
Nico Huber88da05e2019-09-16 21:03:20 +020097 function Highest_Dotclock (Configs : Pipe_Configs) return Frequency_Type
98 is
99 Max : Frequency_Type := Frequency_Type'First;
100 begin
101 for I in Pipe_Index loop
102 if Configs (I).Port /= Disabled and
103 Max < Configs (I).Mode.Dotclock
104 then
105 Max := Configs (I).Mode.Dotclock;
106 end if;
107 end loop;
108 return Max;
109 end Highest_Dotclock;
110
111 procedure Limit_Dotclocks
112 (Configs : in out Pipe_Configs;
113 Max : in Frequency_Type) is
114 begin
115 for I in Pipe_Index loop
116 if Configs (I).Port /= Disabled and
117 Max < Configs (I).Mode.Dotclock
118 then
119 Configs (I).Mode.Dotclock := Max;
120 end if;
121 end loop;
122 end Limit_Dotclocks;
123
Nico Huber8c45bcf2016-11-20 17:30:57 +0100124 ----------------------------------------------------------------------------
125
126 -- Prepares link rate and lane count settings for an FDI connection.
127 procedure Configure_FDI_Link
128 (Port_Cfg : in out Port_Config;
129 Success : out Boolean)
Nico Huber9a4c4c32019-09-16 22:05:11 +0200130 with
131 Post =>
132 Port_Cfg.Mode.H_Visible = Port_Cfg'Old.Mode.H_Visible and
133 Port_Cfg.Mode.V_Visible = Port_Cfg'Old.Mode.V_Visible
Nico Huber8c45bcf2016-11-20 17:30:57 +0100134 is
Nico Huber9a4c4c32019-09-16 22:05:11 +0200135 FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
136 Enabled : Boolean;
137 begin
138 Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
139 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
140 Config.FDI_Lane_Count (Port_Cfg.Port);
141 Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
142
143 if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100144 -- if DIGI_D enabled: (FDI names are off by one)
145 Registers.Is_Set_Mask
146 (Register => Registers.FDI_TX_CTL_C,
147 Mask => FDI_TX_CTL_FDI_TX_ENABLE,
148 Result => Enabled);
149 if Enabled then
150 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
151 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100152 end if;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200153
Nico Huber8c45bcf2016-11-20 17:30:57 +0100154 DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
155 end Configure_FDI_Link;
156
157 -- Derives an internal port config.
158 --
159 -- This is where the magic happens that hides the hardware details
160 -- from libgfxinit's users. We have to map the pipe (Pipe_Index),
161 -- the user visible port (Port_Type) and the modeline (Mode_Type)
162 -- that we are supposed to output to an internal representation
163 -- (Port_Config) that applies to the selected hardware generation
164 -- (in GMA.Config).
165 procedure Fill_Port_Config
166 (Port_Cfg : out Port_Config;
167 Pipe : in Pipe_Index;
168 Port : in Port_Type;
169 Mode : in Mode_Type;
170 Success : out Boolean)
171 is
172 begin
173 Success :=
Nico Huberd58de7d2018-06-07 23:06:55 +0200174 (Config.Has_Tertiary_Pipe or Pipe <= Secondary) and then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100175 Config.Valid_Port (Port) and then
176 Port /= Disabled; -- Valid_Port should already cover this, but the
177 -- array is writeable, so it's hard to prove this.
178
179 if Success then
180 Port_Cfg := Port_Config'
181 (Port => To_GPU_Port (Pipe, Port),
182 PCH_Port => To_PCH_Port (Port),
183 Display => To_Display_Type (Port),
Nico Huber2bbd6e72020-01-07 18:22:59 +0100184 Panel => To_Panel (Port),
Nico Huber8c45bcf2016-11-20 17:30:57 +0100185 Mode => Mode,
186 Is_FDI => Config.Is_FDI_Port (Port),
187 FDI => Default_DP,
188 DP => Default_DP);
189
Nico Huber02cfbb32017-01-09 17:41:18 +0100190 if Port_Cfg.Mode.BPC = Auto_BPC then
191 Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100192 end if;
193
Nico Huber02cfbb32017-01-09 17:41:18 +0100194 if Port_Cfg.Display = HDMI then
195 declare
196 pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
197 / Port_Cfg.Mode.BPC >= Frequency_Type'First);
198 Max_Dotclock : constant Frequency_Type :=
199 Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
200 begin
201 if Port_Cfg.Mode.Dotclock > Max_Dotclock then
202 pragma Debug (Debug.Put ("Dotclock "));
203 pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
204 pragma Debug (Debug.Put (" too high, limiting to "));
205 pragma Debug (Debug.Put_Int64 (Max_Dotclock));
206 pragma Debug (Debug.Put_Line ("."));
207 Port_Cfg.Mode.Dotclock := Max_Dotclock;
208 end if;
209 end;
210 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100211
Nico Huber02cfbb32017-01-09 17:41:18 +0100212 if Port_Cfg.Is_FDI then
213 Configure_FDI_Link (Port_Cfg, Success);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100214 end if;
215 else
216 Port_Cfg := Port_Config'
217 (Port => GPU_Port'First,
218 PCH_Port => PCH_Port'First,
219 Display => Display_Type'First,
Nico Huber2bbd6e72020-01-07 18:22:59 +0100220 Panel => No_Panel,
Nico Huber8c45bcf2016-11-20 17:30:57 +0100221 Mode => Invalid_Mode,
222 Is_FDI => False,
223 FDI => Default_DP,
224 DP => Default_DP);
225 end if;
226 end Fill_Port_Config;
227
228 ----------------------------------------------------------------------------
229
230 -- Validates that a given configuration should work with
231 -- a given framebuffer.
232 function Validate_Config
Nico Huberf361ec82018-06-02 18:01:45 +0200233 (FB : Framebuffer_Type;
234 Mode : Mode_Type;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200235 Pipe : Pipe_Index)
Nico Huber8c45bcf2016-11-20 17:30:57 +0100236 return Boolean
237 is
238 begin
239 -- No downscaling
240 -- Respect maximum scalable width
241 -- VGA plane is only allowed on the primary pipe
242 -- Only 32bpp RGB (ignored for VGA plane)
Nico Huber0164b022017-08-24 15:12:51 +0200243 -- Stride must be big enough and a multiple of 64 bytes or the tile size
244 -- (ignored for VGA plane)
Nico Huberab69e362018-05-29 21:20:30 +0200245 -- Y-Tiling and rotation are only supported on newer generations (with
Nico Huber9b479412017-08-27 11:55:56 +0200246 -- Plane_Control)
247 -- 90 degree rotations are only supported with Y-tiling
Nico Huber8c45bcf2016-11-20 17:30:57 +0100248 return
Nico Hubercbbaade2018-01-02 13:59:36 +0100249 ((Rotated_Width (FB) = Mode.H_Visible and
250 Rotated_Height (FB) = Mode.V_Visible) or
Nico Huber9a4c4c32019-09-16 22:05:11 +0200251 (Rotated_Width (FB) <= Config.Maximum_Scalable_Width (Pipe) and
Nico Hubercbbaade2018-01-02 13:59:36 +0100252 Rotated_Width (FB) <= Mode.H_Visible and
253 Rotated_Height (FB) <= Mode.V_Visible)) and
Nico Huber9b479412017-08-27 11:55:56 +0200254 (FB.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary) and
255 (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
256 (FB.BPC = 8 and Valid_Stride (FB) and
257 (Config.Has_Plane_Control or
Nico Huberab69e362018-05-29 21:20:30 +0200258 (FB.Tiling /= Y_Tiled and FB.Rotation = No_Rotation)) and
Nico Huber9b479412017-08-27 11:55:56 +0200259 (FB.Tiling = Y_Tiled or not Rotation_90 (FB))));
Nico Huber8c45bcf2016-11-20 17:30:57 +0100260 end Validate_Config;
261
262end HW.GFX.GMA.Config_Helpers;