gma: Add `Cannon_Point` PCH

It almost behaves the same as its predecessors Union and Sunrise
Point. GMBUS pins and panel and backlight controls are updated to
those of Broxton. It also allows an alternative `Raw Clock` of
19.2MHz.

Change-Id: I86fe26a351d2c3c736b6acc85f718fd103d276bb
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/libgfxinit/+/48763
Reviewed-by: Michael Niewöhner <foss@mniewoehner.de>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template
index 820bf0e..1177218 100644
--- a/common/hw-gfx-gma-config.ads.template
+++ b/common/hw-gfx-gma-config.ads.template
@@ -56,7 +56,7 @@
          when Ironlake  => Cougar_Point,
          when Haswell   => Lynx_Point,
          when Broxton   => No_PCH,
-         when Skylake   => Sunrise_Point);
+         when Skylake   => Cannon_Point);
    subtype Gen_PCH_Type is PCH_Type range PCH_First .. PCH_Last;
 
    PCH : constant Gen_PCH_Type := <<PCH>>;
@@ -167,6 +167,7 @@
 
    Cougar_Point_On   : <genbool> :=
      ((Gen_Ironlake and then PCH >= Cougar_Point) or Haswell_On);
+   Cannon_Point_On   : <genbool> := Skylake_On and then PCH >= Cannon_Point;
 
    ----------------------------------------------------------------------------
 
@@ -207,8 +208,9 @@
    Has_PP_Port_Select            : <genbool> := Up_To_Ironlake;
    Use_PP_VDD_Override           : <genbool> := Up_To_Ironlake;
    Has_PCH_Panel_Power           : <genbool> := Ironlake_On;
-   Has_PP_Divisor_Reg            : <genbool> := not Gen_Broxton;
-   Has_New_Backlight_Control     : <genbool> := Gen_Broxton;
+   Has_PP_Divisor_Reg            : <genbool> :=
+     (not Gen_Broxton and not Cannon_Point_On);
+   Has_New_Backlight_Control     : <genbool> := Gen_Broxton or Cannon_Point_On;
 
    ----------- PCH/FDI: ---------
    Has_PCH                       : <genbool> := PCH /= No_PCH;
@@ -236,6 +238,7 @@
    Has_GMCH_Mobile_VCO           : <g45bool> := GMCH_GM45;
    Has_Broadwell_CDClk           : <hswbool> := CPU_Broadwell;
    Can_Switch_CDClk              : <hswbool> := Broadwell_On;
+   Has_Fractional_RawClk         : <genbool> := Cannon_Point_On;
 
    ----------- DDI: -------------
    End_EDP_Training_Late         : <genbool> := Gen_Haswell;
@@ -264,7 +267,7 @@
 
    ----------- GMBUS: -----------
    Ungate_GMBUS_Unit_Level       : <genbool> := Skylake_On;
-   GMBUS_Alternative_Pins        : <genbool> := Gen_Broxton;
+   GMBUS_Alternative_Pins        : <genbool> := Gen_Broxton or Cannon_Point_On;
    Has_PCH_GMBUS                 : <genbool> := Ironlake_On;
 
    ----------- Power: -----------
diff --git a/common/hw-gfx-gma-i2c.adb b/common/hw-gfx-gma-i2c.adb
index a958e26..67e90ab 100644
--- a/common/hw-gfx-gma-i2c.adb
+++ b/common/hw-gfx-gma-i2c.adb
@@ -38,9 +38,10 @@
    GMBUS0_PIN_PAIR_SELECT_DIGI_C    : constant :=   4 * 2 **  0;
    GMBUS0_PIN_PAIR_SELECT_DIGI_B    : constant :=   5 * 2 **  0;
    GMBUS0_PIN_PAIR_SELECT_DIGI_D    : constant :=   6 * 2 **  0;
-   -- Broxton uses different pins
+   -- Broxton and later use different pins
    GMBUS0_PIN_PAIR_SELECT_BXT_B     : constant :=   1 * 2 **  0;
    GMBUS0_PIN_PAIR_SELECT_BXT_C     : constant :=   2 * 2 **  0;
+   GMBUS0_PIN_PAIR_SELECT_BXT_D     : constant :=   3 * 2 **  0;
 
    GMBUS1_SOFTWARE_CLEAR_INTERRUPT  : constant :=   1 * 2 ** 31;
    GMBUS1_SOFTWARE_READY            : constant :=   1 * 2 ** 30;
@@ -109,6 +110,7 @@
            (case Port is
                when PCH_HDMI_B   => GMBUS0_PIN_PAIR_SELECT_BXT_B,
                when PCH_HDMI_C   => GMBUS0_PIN_PAIR_SELECT_BXT_C,
+               when PCH_HDMI_D   => GMBUS0_PIN_PAIR_SELECT_BXT_D,
                when others       => GMBUS0_PIN_PAIR_SELECT_NONE)
          else
            (case Port is
diff --git a/common/hw-gfx-gma.adb b/common/hw-gfx-gma.adb
index 3305aeb..d1ae1a0 100644
--- a/common/hw-gfx-gma.adb
+++ b/common/hw-gfx-gma.adb
@@ -85,12 +85,26 @@
 
    ----------------------------------------------------------------------------
 
-   PCH_RAWCLK_FREQ_MASK                : constant := 16#3ff# * 2 ** 0;
+   PCH_RAWCLK_FREQ_MASK : constant :=
+     (if Config.Has_Fractional_RawClk then 16#3fff# * 2 ** 16 else 16#3ff# * 2 ** 0);
 
    function PCH_RAWCLK_FREQ (Freq : Frequency_Type) return Word32
    is
    begin
-      return Word32 (Freq / 1_000_000);
+      if Config.Has_Fractional_RawClk then
+         declare
+            Fraction_K : constant Int64 := Freq / 1_000 mod 1_000;
+            Freq32 : Word32 := Shift_Left (Word32 (Freq / 1_000_000), 16);
+         begin
+            if Fraction_K /= 0 then
+               Freq32 := Freq32 or Shift_Left
+                 (Word32 (Div_Round_Closest (1_000, Fraction_K) - 1), 26);
+            end if;
+            return Freq32;
+         end;
+      else
+         return Word32 (Freq / 1_000_000);
+      end if;
    end PCH_RAWCLK_FREQ;
 
    ----------------------------------------------------------------------------
diff --git a/common/hw-gfx-gma.ads b/common/hw-gfx-gma.ads
index b6c491f..5c63942 100644
--- a/common/hw-gfx-gma.ads
+++ b/common/hw-gfx-gma.ads
@@ -54,7 +54,8 @@
       Ibex_Peak,
       Cougar_Point,     -- Panther Point compatible
       Lynx_Point,       -- Wildcat Point compatible
-      Sunrise_Point);   -- Union Point compatible
+      Sunrise_Point,    -- Union Point compatible
+      Cannon_Point);
 
    type Port_Type is
      (Disabled,
diff --git a/common/skylake/hw-gfx-gma-power_and_clocks.adb b/common/skylake/hw-gfx-gma-power_and_clocks.adb
index 4c8b6ac..edbaf00 100644
--- a/common/skylake/hw-gfx-gma-power_and_clocks.adb
+++ b/common/skylake/hw-gfx-gma-power_and_clocks.adb
@@ -40,6 +40,8 @@
    DFSM_DISPLAY_CDCLK_LIMIT_337_5MHZ   : constant := 3 * 2 ** 23;
    DFSM_DISPLAY_CDCLK_LIMIT_MASK       : constant := 3 * 2 ** 23;
 
+   SFUSE_STRAP_RAW_FREQUENCY           : constant := 1 * 2 **  8;
+
    type Power_Domain_Values is array (Power_Domain) of Word32;
    PWR_WELL_CTL_POWER_REQUEST : constant Power_Domain_Values :=
      (MISC_IO  => 1 * 2 **  1,
@@ -309,6 +311,22 @@
       Config.CDClk := CDClk;
    end Set_CDClk;
 
+   procedure Get_Raw_Clock (Raw_Clock : out Frequency_Type)
+   is
+      Freq_24MHz : Boolean;
+   begin
+      Raw_Clock := Config.Default_RawClk_Freq;
+      if Config.Has_Fractional_RawClk then
+         Registers.Is_Set_Mask
+           (Register => Registers.SFUSE_STRAP,
+            Mask     => SFUSE_STRAP_RAW_FREQUENCY,
+            Result   => Freq_24MHz);
+         if not Freq_24MHz then
+            Raw_Clock := 19_200_000;
+         end if;
+      end if;
+   end Get_Raw_Clock;
+
    procedure Initialize is
    begin
       Registers.Set_Mask
@@ -337,7 +355,7 @@
       Get_Max_CDClk (Config.Max_CDClk);
       Set_CDClk (Config.Default_CDClk_Freq);
 
-      Config.Raw_Clock := Config.Default_RawClk_Freq;
+      Get_Raw_Clock (Config.Raw_Clock);
    end Initialize;
 
    procedure Limit_Dotclocks