gma pcode: Move and revise mailbox handling
Unify the PCODE mailbox implementations (Linux' i915 uses the same
implementation since Sandy Bridge, too) and add `Wait` and `Success`
parameters so we can act correctly if something failed. This adds
a lot of boilerplate. But we keep it contained in the new package
`PCode` and the code outside it looks cleaner and handles errors
more gracefully.
In GNATprove, we track state of the mailbox' readiness in a ghost
variable `Mailbox_Ready`. This allows us to skip the initial wait
loop if we know that we already waited at the end of a previous
call. The first call to a mailbox procedure has to be made with
`Wait_Ready => True`.
Also, start to experiment with a `use` clause for the `Register`
package. It allows us to write a little more condensed code, with-
out sacrificing much (in this program we can expect that `Read`/
`Write` means register access?) So far it looks good?
Change-Id: I5daa3effb7ab774e4a35bd8794b0f67f57e4caa4
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/libgfxinit/+/35710
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
diff --git a/common/skylake/hw-gfx-gma-power_and_clocks_skylake.adb b/common/skylake/hw-gfx-gma-power_and_clocks_skylake.adb
index c6eb2cf..2ab7f21 100644
--- a/common/skylake/hw-gfx-gma-power_and_clocks_skylake.adb
+++ b/common/skylake/hw-gfx-gma-power_and_clocks_skylake.adb
@@ -18,6 +18,7 @@
with HW.Debug;
with HW.GFX.GMA.Config;
with HW.GFX.GMA.Registers;
+with HW.GFX.GMA.PCode;
with HW.GFX.GMA.Power_And_Clocks_Haswell;
use type HW.Word64;
@@ -86,8 +87,6 @@
SKL_CDCLK_PREPARE_FOR_CHANGE : constant := 3;
SKL_CDCLK_READY_FOR_CHANGE : constant := 1;
- GT_MAILBOX_READY : constant := 1 * 2 ** 31;
-
function CDCLK_CTL_CD_FREQ_DECIMAL
(Freq : Pos16;
Plus_Half : Boolean)
@@ -98,22 +97,6 @@
----------------------------------------------------------------------------
- procedure GT_Mailbox_Write (MBox : Word32; Value : Word64) is
- begin
- pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
-
- Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
- Registers.Write
- (Registers.GT_MAILBOX_DATA, Word32 (Value and 16#ffff_ffff#));
- Registers.Write
- (Registers.GT_MAILBOX_DATA_1, Word32 (Shift_Right (Value, 32)));
- Registers.Write (Registers.GT_MAILBOX, GT_MAILBOX_READY or MBox);
-
- Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
- end GT_Mailbox_Write;
-
- ----------------------------------------------------------------------------
-
procedure PD_Off (PD : Power_Domain)
is
Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
@@ -251,10 +234,7 @@
procedure Initialize
is
- CDClk_Change_Timeout : Time.T;
- Timed_Out : Boolean;
-
- MBox_Data0 : Word32;
+ Success : Boolean;
begin
Registers.Set_Mask
(Register => Registers.NDE_RSTWRN_OPT,
@@ -282,29 +262,20 @@
(Register => Registers.LCPLL1_CTL,
Mask => LCPLL1_CTL_PLL_LOCK);
- CDClk_Change_Timeout := Time.MS_From_Now (3);
- Timed_Out := False;
- loop
- GT_Mailbox_Write
- (MBox => SKL_PCODE_CDCLK_CONTROL,
- Value => SKL_CDCLK_PREPARE_FOR_CHANGE);
- Registers.Read (Registers.GT_MAILBOX_DATA, MBox_Data0);
- if (MBox_Data0 and SKL_CDCLK_READY_FOR_CHANGE) /= 0 then
- -- Ignore timeout if we succeeded anyway.
- Timed_Out := False;
- exit;
- end if;
- exit when Timed_Out;
+ PCode.Mailbox_Request
+ (MBox => SKL_PCODE_CDCLK_CONTROL,
+ Command => SKL_CDCLK_PREPARE_FOR_CHANGE,
+ Reply_Mask => SKL_CDCLK_READY_FOR_CHANGE,
+ Wait_Ready => True,
+ Success => Success);
- Timed_Out := Time.Timed_Out (CDClk_Change_Timeout);
- end loop;
- pragma Debug (Timed_Out, Debug.Put_Line
- ("ERROR: PCODE not ready for frequency change after 3ms."));
+ pragma Debug (not Success, Debug.Put_Line
+ ("ERROR: PCODE not ready for frequency change."));
- if not Timed_Out then
- GT_Mailbox_Write
+ if Success then
+ PCode.Mailbox_Write
(MBox => SKL_PCODE_CDCLK_CONTROL,
- Value => 16#0000_0000#); -- 0 - 337.5MHz
+ Command => 16#0000_0000#); -- 0 - 337.5MHz
-- 1 - 450.0MHz
-- 2 - 540.0MHz
-- 3 - 675.0MHz