gma: Refactor Update_Outputs()
In Update_Outputs(), we used to have two steps, iterating over
all available pipes: We disabled all pipes whose mode changed
or that would be disabled otherwise. Then, we enabled all pipes
with new modes.
As checks for validity of the configurations were only done on
demand in the second step, that left us with no knowledge about
what configs would actually be tried. To make this information
available for future work, we add a validation step before the
existing two. That gives us:
1. Validate all new configs
2. Disable pipes
- whose mode changed
- that were disconnected
- whose config didn't validate
3. Enable/update pipes with new configs
This way, we can make global decisions ahead of 2. and 3. based
on the remaining, _valid_ configurations.
We had to turn Pipe_Setup.Scaler_Available() into a Reserve_Scaler()
so we can keep track which new configuration gets to use a scaler.
G45 is still the only case where we have less scalers than pipes
available. To keep that transparent to Update_Outputs() we add the
opaque type `Scaler_Reservation`.
The `Loop_Invariant` of 1. allows us to keep the validation
in mind, to satisfy pre-conditions of the various steps ahead.
To not lose the validation, Fill_Port_Config() needs a post
condition and a little restructuring to prove it.
Change-Id: I079ae8f85c821a272b5d095c1ef437ee804aa9ac
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/libgfxinit/+/35528
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/common/hw-gfx-gma.adb b/common/hw-gfx-gma.adb
index dbdee5c..269feec 100644
--- a/common/hw-gfx-gma.adb
+++ b/common/hw-gfx-gma.adb
@@ -1,5 +1,5 @@
--
--- Copyright (C) 2014-2018 secunet Security Networks AG
+-- Copyright (C) 2014-2019 secunet Security Networks AG
-- Copyright (C) 2017 Nico Huber <nico.h@gmx.de>
--
-- This program is free software; you can redistribute it and/or modify
@@ -98,10 +98,11 @@
Pipe_Cfg : in Pipe_Config;
Success : out Boolean)
with
- Pre => Pipe_Cfg.Port in Active_Port_Type
+ Pre =>
+ Pipe_Cfg.Port in Active_Port_Type and
+ Config_Helpers.Valid_FB (Pipe_Cfg.Framebuffer, Pipe_Cfg.Mode)
is
Port_Cfg : Port_Config;
- Scaler_Available : Boolean;
begin
pragma Debug (Debug.New_Line);
pragma Debug (Debug.Put_Line
@@ -111,12 +112,6 @@
(Port_Cfg, Pipe, Pipe_Cfg.Port, Pipe_Cfg.Mode, Success);
if Success then
- Display_Controller.Scaler_Available (Scaler_Available, Pipe);
- Success := Config_Helpers.Validate_Config
- (Pipe_Cfg.Framebuffer, Port_Cfg.Mode, Pipe, Scaler_Available);
- end if;
-
- if Success then
Connector_Info.Preferred_Link_Setting (Port_Cfg, Success);
end if;
@@ -223,19 +218,12 @@
end if;
end Check_HPD;
- Power_Changed : Boolean := False;
- Old_Configs : Pipe_Configs;
+ Scaler_Reservation : Display_Controller.Scaler_Reservation :=
+ Display_Controller.Null_Scaler_Reservation;
- -- Only called when we actually tried to change something
- -- so we don't congest the log with unnecessary messages.
- procedure Update_Power
- is
- begin
- if not Power_Changed then
- Power_And_Clocks.Power_Up (Old_Configs, Configs);
- Power_Changed := True;
- end if;
- end Update_Power;
+ Update_Power : Boolean := False;
+ Old_Configs,
+ New_Configs : Pipe_Configs;
function Full_Update (Cur_Config, New_Config : Pipe_Config) return Boolean
is
@@ -255,13 +243,48 @@
end Full_Update;
begin
Old_Configs := Cur_Configs;
+ New_Configs := Configs;
+
+ -- validate new configs, filter invalid configs and those waiting for HPD
+ for Pipe in Pipe_Index loop
+ declare
+ Success : Boolean := True;
+ Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
+ New_Config : Pipe_Config renames New_Configs (Pipe);
+ begin
+ if New_Config.Port /= Disabled then
+ if Wait_For_HPD (New_Config.Port) then
+ Check_HPD (New_Config.Port, Success);
+ Wait_For_HPD (New_Config.Port) := not Success;
+ end if;
+
+ Success := Success and then
+ Config_Helpers.Validate_Config
+ (New_Config.Framebuffer, New_Config.Mode, Pipe);
+
+ if Success and then Requires_Scaling (New_Config) then
+ Display_Controller.Reserve_Scaler
+ (Success, Scaler_Reservation, Pipe);
+ end if;
+
+ if not Success then
+ New_Config.Port := Disabled;
+ end if;
+ end if;
+ end;
+ pragma Loop_Invariant
+ (for all P in Pipe_Index'First .. Pipe =>
+ New_Configs (P).Port = Disabled or
+ Config_Helpers.Valid_FB
+ (New_Configs (P).Framebuffer, New_Configs (P).Mode));
+ end loop;
-- disable all pipes that changed or had a hot-plug event
for Pipe in Pipe_Index loop
declare
Unplug_Detected : Boolean;
Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
- New_Config : Pipe_Config renames Configs (Pipe);
+ New_Config : Pipe_Config renames New_Configs (Pipe);
begin
if Cur_Config.Port /= Disabled then
Check_HPD (Cur_Config.Port, Unplug_Detected);
@@ -269,7 +292,7 @@
if Full_Update (Cur_Config, New_Config) or Unplug_Detected then
Disable_Output (Pipe, Cur_Config);
Cur_Config.Port := Disabled;
- Update_Power;
+ Update_Power := True;
end if;
end if;
end;
@@ -279,25 +302,17 @@
for Pipe in Pipe_Index loop
declare
Success : Boolean;
- Scaler_Available : Boolean;
Cur_Config : Pipe_Config renames Cur_Configs (Pipe);
- New_Config : Pipe_Config renames Configs (Pipe);
+ New_Config : Pipe_Config renames New_Configs (Pipe);
begin
+ -- full update
if New_Config.Port /= Disabled and
Full_Update (Cur_Config, New_Config)
then
- if Wait_For_HPD (New_Config.Port) then
- Check_HPD (New_Config.Port, Success);
- Wait_For_HPD (New_Config.Port) := not Success;
- else
- Success := True;
- end if;
+ Power_And_Clocks.Power_Up (Old_Configs, New_Configs);
+ Update_Power := True;
- if Success then
- Update_Power;
- Enable_Output (Pipe, New_Config, Success);
- end if;
-
+ Enable_Output (Pipe, New_Config, Success);
if Success then
Cur_Config := New_Config;
end if;
@@ -306,23 +321,17 @@
elsif New_Config.Port /= Disabled and
Cur_Config.Framebuffer /= New_Config.Framebuffer
then
- Display_Controller.Scaler_Available (Scaler_Available, Pipe);
- if Config_Helpers.Validate_Config
- (New_Config.Framebuffer, New_Config.Mode,
- Pipe, Scaler_Available)
- then
- Display_Controller.Setup_FB
- (Pipe, New_Config.Mode, New_Config.Framebuffer);
- Display_Controller.Update_Cursor
- (Pipe, New_Config.Framebuffer, New_Config.Cursor);
- Cur_Config := New_Config;
- end if;
+ Display_Controller.Setup_FB
+ (Pipe, New_Config.Mode, New_Config.Framebuffer);
+ Display_Controller.Update_Cursor
+ (Pipe, New_Config.Framebuffer, New_Config.Cursor);
+ Cur_Config := New_Config;
end if;
end;
end loop;
- if Power_Changed then
- Power_And_Clocks.Power_Down (Old_Configs, Configs, Cur_Configs);
+ if Update_Power then
+ Power_And_Clocks.Power_Down (Old_Configs, New_Configs, Cur_Configs);
end if;
end Update_Outputs;