blob: 07fa087a14e5f21e7c20cb5740486b300cf08f97 [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
15with HW.GFX.GMA.Config;
16with HW.GFX.GMA.Connector_Info;
17with HW.GFX.GMA.DP_Info;
18with HW.GFX.GMA.Registers;
19
20with HW.Debug;
21
22package body HW.GFX.GMA.Config_Helpers
23is
24
25 function To_GPU_Port
26 (Pipe : Pipe_Index;
27 Port : Active_Port_Type)
28 return GPU_Port
29 is
30 begin
31 return
Nico Huber6621a142018-06-07 23:56:54 +020032 (case Config.Gen is
33 when G45 => -- everything on GMCH
Arthur Heymans73ea0322018-03-28 17:17:07 +020034 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010035 when LVDS => LVDS,
36 when eDP => DIGI_A, -- n/a, actually
Arthur Heymans73ea0322018-03-28 17:17:07 +020037 when HDMI1 | DP1 => DIGI_B,
38 when HDMI2 | DP2 => DIGI_C,
39 when HDMI3 | DP3 => DIGI_D,
40 when Analog => VGA),
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)),
Nico Huber6621a142018-06-07 23:56:54 +020049 when others => -- everything but VGA directly on CPU
Nico Huber8c45bcf2016-11-20 17:30:57 +010050 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010051 when LVDS => LVDS, -- n/a, actually
52 when eDP => DIGI_A,
Nico Huber8c45bcf2016-11-20 17:30:57 +010053 when HDMI1 | DP1 => DIGI_B,
54 when HDMI2 | DP2 => DIGI_C,
55 when HDMI3 | DP3 => DIGI_D,
56 when Analog => DIGI_E));
57 end To_GPU_Port;
58
59 function To_PCH_Port (Port : Active_Port_Type) return PCH_Port
60 is
61 begin
62 return
63 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010064 when LVDS => PCH_LVDS,
65 when eDP => PCH_LVDS, -- n/a, actually
Nico Huber8c45bcf2016-11-20 17:30:57 +010066 when Analog => PCH_DAC,
67 when HDMI1 => PCH_HDMI_B,
68 when HDMI2 => PCH_HDMI_C,
69 when HDMI3 => PCH_HDMI_D,
70 when DP1 => PCH_DP_B,
71 when DP2 => PCH_DP_C,
72 when DP3 => PCH_DP_D);
73 end To_PCH_Port;
74
75 function To_Display_Type (Port : Active_Port_Type) return Display_Type
76 is
77 begin
78 return Display_Type'
79 (case Port is
Nico Huber8beafd72020-01-07 14:59:44 +010080 when LVDS => LVDS,
81 when eDP => DP,
Nico Huber8c45bcf2016-11-20 17:30:57 +010082 when Analog => VGA,
83 when HDMI1 .. HDMI3 => HDMI,
84 when DP1 .. DP3 => DP);
85 end To_Display_Type;
86
Nico Huber88da05e2019-09-16 21:03:20 +020087 function Highest_Dotclock (Configs : Pipe_Configs) return Frequency_Type
88 is
89 Max : Frequency_Type := Frequency_Type'First;
90 begin
91 for I in Pipe_Index loop
92 if Configs (I).Port /= Disabled and
93 Max < Configs (I).Mode.Dotclock
94 then
95 Max := Configs (I).Mode.Dotclock;
96 end if;
97 end loop;
98 return Max;
99 end Highest_Dotclock;
100
101 procedure Limit_Dotclocks
102 (Configs : in out Pipe_Configs;
103 Max : in Frequency_Type) is
104 begin
105 for I in Pipe_Index loop
106 if Configs (I).Port /= Disabled and
107 Max < Configs (I).Mode.Dotclock
108 then
109 Configs (I).Mode.Dotclock := Max;
110 end if;
111 end loop;
112 end Limit_Dotclocks;
113
Nico Huber8c45bcf2016-11-20 17:30:57 +0100114 ----------------------------------------------------------------------------
115
116 -- Prepares link rate and lane count settings for an FDI connection.
117 procedure Configure_FDI_Link
118 (Port_Cfg : in out Port_Config;
119 Success : out Boolean)
Nico Huber9a4c4c32019-09-16 22:05:11 +0200120 with
121 Post =>
122 Port_Cfg.Mode.H_Visible = Port_Cfg'Old.Mode.H_Visible and
123 Port_Cfg.Mode.V_Visible = Port_Cfg'Old.Mode.V_Visible
Nico Huber8c45bcf2016-11-20 17:30:57 +0100124 is
Nico Huber9a4c4c32019-09-16 22:05:11 +0200125 FDI_TX_CTL_FDI_TX_ENABLE : constant := 1 * 2 ** 31;
126 Enabled : Boolean;
127 begin
128 Port_Cfg.FDI.Receiver_Caps.Max_Link_Rate := DP_Bandwidth_2_7;
129 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count :=
130 Config.FDI_Lane_Count (Port_Cfg.Port);
131 Port_Cfg.FDI.Receiver_Caps.Enhanced_Framing := True;
132
133 if Config.Has_FDI_C and then Port_Cfg.Port = DIGI_C then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100134 -- if DIGI_D enabled: (FDI names are off by one)
135 Registers.Is_Set_Mask
136 (Register => Registers.FDI_TX_CTL_C,
137 Mask => FDI_TX_CTL_FDI_TX_ENABLE,
138 Result => Enabled);
139 if Enabled then
140 Port_Cfg.FDI.Receiver_Caps.Max_Lane_Count := DP_Lane_Count_2;
141 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100142 end if;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200143
Nico Huber8c45bcf2016-11-20 17:30:57 +0100144 DP_Info.Preferred_Link_Setting (Port_Cfg.FDI, Port_Cfg.Mode, Success);
145 end Configure_FDI_Link;
146
147 -- Derives an internal port config.
148 --
149 -- This is where the magic happens that hides the hardware details
150 -- from libgfxinit's users. We have to map the pipe (Pipe_Index),
151 -- the user visible port (Port_Type) and the modeline (Mode_Type)
152 -- that we are supposed to output to an internal representation
153 -- (Port_Config) that applies to the selected hardware generation
154 -- (in GMA.Config).
155 procedure Fill_Port_Config
156 (Port_Cfg : out Port_Config;
157 Pipe : in Pipe_Index;
158 Port : in Port_Type;
159 Mode : in Mode_Type;
160 Success : out Boolean)
161 is
162 begin
163 Success :=
Nico Huberd58de7d2018-06-07 23:06:55 +0200164 (Config.Has_Tertiary_Pipe or Pipe <= Secondary) and then
Nico Huber8c45bcf2016-11-20 17:30:57 +0100165 Config.Valid_Port (Port) and then
166 Port /= Disabled; -- Valid_Port should already cover this, but the
167 -- array is writeable, so it's hard to prove this.
168
169 if Success then
170 Port_Cfg := Port_Config'
171 (Port => To_GPU_Port (Pipe, Port),
172 PCH_Port => To_PCH_Port (Port),
173 Display => To_Display_Type (Port),
174 Mode => Mode,
175 Is_FDI => Config.Is_FDI_Port (Port),
176 FDI => Default_DP,
177 DP => Default_DP);
178
Nico Huber02cfbb32017-01-09 17:41:18 +0100179 if Port_Cfg.Mode.BPC = Auto_BPC then
180 Port_Cfg.Mode.BPC := Connector_Info.Default_BPC (Port_Cfg);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100181 end if;
182
Nico Huber02cfbb32017-01-09 17:41:18 +0100183 if Port_Cfg.Display = HDMI then
184 declare
185 pragma Assert (Config.HDMI_Max_Clock_24bpp * 8
186 / Port_Cfg.Mode.BPC >= Frequency_Type'First);
187 Max_Dotclock : constant Frequency_Type :=
188 Config.HDMI_Max_Clock_24bpp * 8 / Port_Cfg.Mode.BPC;
189 begin
190 if Port_Cfg.Mode.Dotclock > Max_Dotclock then
191 pragma Debug (Debug.Put ("Dotclock "));
192 pragma Debug (Debug.Put_Int64 (Port_Cfg.Mode.Dotclock));
193 pragma Debug (Debug.Put (" too high, limiting to "));
194 pragma Debug (Debug.Put_Int64 (Max_Dotclock));
195 pragma Debug (Debug.Put_Line ("."));
196 Port_Cfg.Mode.Dotclock := Max_Dotclock;
197 end if;
198 end;
199 end if;
Nico Huber8c45bcf2016-11-20 17:30:57 +0100200
Nico Huber02cfbb32017-01-09 17:41:18 +0100201 if Port_Cfg.Is_FDI then
202 Configure_FDI_Link (Port_Cfg, Success);
Nico Huber8c45bcf2016-11-20 17:30:57 +0100203 end if;
204 else
205 Port_Cfg := Port_Config'
206 (Port => GPU_Port'First,
207 PCH_Port => PCH_Port'First,
208 Display => Display_Type'First,
209 Mode => Invalid_Mode,
210 Is_FDI => False,
211 FDI => Default_DP,
212 DP => Default_DP);
213 end if;
214 end Fill_Port_Config;
215
216 ----------------------------------------------------------------------------
217
218 -- Validates that a given configuration should work with
219 -- a given framebuffer.
220 function Validate_Config
Nico Huberf361ec82018-06-02 18:01:45 +0200221 (FB : Framebuffer_Type;
222 Mode : Mode_Type;
Nico Huber9a4c4c32019-09-16 22:05:11 +0200223 Pipe : Pipe_Index)
Nico Huber8c45bcf2016-11-20 17:30:57 +0100224 return Boolean
225 is
226 begin
227 -- No downscaling
228 -- Respect maximum scalable width
229 -- VGA plane is only allowed on the primary pipe
230 -- Only 32bpp RGB (ignored for VGA plane)
Nico Huber0164b022017-08-24 15:12:51 +0200231 -- Stride must be big enough and a multiple of 64 bytes or the tile size
232 -- (ignored for VGA plane)
Nico Huberab69e362018-05-29 21:20:30 +0200233 -- Y-Tiling and rotation are only supported on newer generations (with
Nico Huber9b479412017-08-27 11:55:56 +0200234 -- Plane_Control)
235 -- 90 degree rotations are only supported with Y-tiling
Nico Huber8c45bcf2016-11-20 17:30:57 +0100236 return
Nico Hubercbbaade2018-01-02 13:59:36 +0100237 ((Rotated_Width (FB) = Mode.H_Visible and
238 Rotated_Height (FB) = Mode.V_Visible) or
Nico Huber9a4c4c32019-09-16 22:05:11 +0200239 (Rotated_Width (FB) <= Config.Maximum_Scalable_Width (Pipe) and
Nico Hubercbbaade2018-01-02 13:59:36 +0100240 Rotated_Width (FB) <= Mode.H_Visible and
241 Rotated_Height (FB) <= Mode.V_Visible)) and
Nico Huber9b479412017-08-27 11:55:56 +0200242 (FB.Offset /= VGA_PLANE_FRAMEBUFFER_OFFSET or Pipe = Primary) and
243 (FB.Offset = VGA_PLANE_FRAMEBUFFER_OFFSET or
244 (FB.BPC = 8 and Valid_Stride (FB) and
245 (Config.Has_Plane_Control or
Nico Huberab69e362018-05-29 21:20:30 +0200246 (FB.Tiling /= Y_Tiled and FB.Rotation = No_Rotation)) and
Nico Huber9b479412017-08-27 11:55:56 +0200247 (FB.Tiling = Y_Tiled or not Rotation_90 (FB))));
Nico Huber8c45bcf2016-11-20 17:30:57 +0100248 end Validate_Config;
249
250end HW.GFX.GMA.Config_Helpers;