| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 1 | -- |
| 2 | -- Copyright (C) 2016 secunet Security Networks AG |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 3 | -- Copyright (C) 2019 Nico Huber <nico.h@gmx.de> |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 4 | -- |
| 5 | -- This program is free software; you can redistribute it and/or modify |
| 6 | -- it under the terms of the GNU General Public License as published by |
| 7 | -- the Free Software Foundation; either version 2 of the License, or |
| 8 | -- (at your option) any later version. |
| 9 | -- |
| 10 | -- This program is distributed in the hope that it will be useful, |
| 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | -- GNU General Public License for more details. |
| 14 | -- |
| 15 | |
| 16 | with HW.Time; |
| 17 | with HW.GFX.GMA.Config; |
| 18 | with HW.GFX.GMA.Registers; |
| 19 | |
| 20 | package body HW.GFX.GMA.Power_And_Clocks is |
| 21 | |
| 22 | FSB_FREQ_SEL_MASK : constant := 7 * 2 ** 0; |
| 23 | CLKCFG_FSB_400 : constant Frequency_Type := 100_000_000; |
| 24 | CLKCFG_FSB_533 : constant Frequency_Type := 133_333_333; |
| 25 | CLKCFG_FSB_667 : constant Frequency_Type := 166_666_666; |
| 26 | CLKCFG_FSB_800 : constant Frequency_Type := 200_000_000; |
| 27 | CLKCFG_FSB_1067 : constant Frequency_Type := 266_666_666; |
| 28 | CLKCFG_FSB_1333 : constant Frequency_Type := 333_333_333; |
| 29 | |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 30 | type Div_Array is array (0 .. 7) of Pos64; |
| 31 | |
| 32 | procedure Get_VCO (VCO : out Int64; Divisors : out Div_Array) |
| 33 | is |
| 34 | G45_3200 : constant Div_Array := (12, 10, 8, 7, 5, 16, others => 1); |
| 35 | G45_4000 : constant Div_Array := (14, 12, 10, 8, 6, 20, others => 1); |
| 36 | G45_4800 : constant Div_Array := (20, 14, 12, 10, 8, 24, others => 1); |
| 37 | G45_5333 : constant Div_Array := (20, 16, 12, 12, 8, 28, others => 1); |
| 38 | G45_Divs : constant array (Natural range 0 .. 7) of Div_Array := |
| 39 | (G45_3200, G45_4000, G45_5333, G45_4800, others => (others => 1)); |
| 40 | |
| 41 | GM45_2667 : constant Div_Array := (12, 8, others => 1); |
| 42 | GM45_3200 : constant Div_Array := (14, 10, others => 1); |
| 43 | GM45_4000 : constant Div_Array := (18, 12, others => 1); |
| 44 | GM45_5333 : constant Div_Array := (24, 16, others => 1); |
| 45 | GM45_Divs : constant array (Natural range 0 .. 7) of Div_Array := |
| 46 | (0 => GM45_3200, 1 => GM45_4000, 2 => GM45_5333, 4 => GM45_2667, |
| 47 | others => (others => 1)); |
| 48 | |
| Arthur Heymans | 3f37cce | 2026-03-03 18:52:12 +0100 | [diff] [blame^] | 49 | -- Crestline (GM965) VCO divisor tables from Linux' i965gm_get_cdclk |
| 50 | CL_3200 : constant Div_Array := (16, 10, 8, others => 1); |
| 51 | CL_4000 : constant Div_Array := (20, 12, 10, others => 1); |
| 52 | CL_5333 : constant Div_Array := (24, 16, 14, others => 1); |
| 53 | CL_Divs : constant array (Natural range 0 .. 7) of Div_Array := |
| 54 | (0 => CL_3200, 1 => CL_4000, 2 => CL_5333, |
| 55 | others => (others => 1)); |
| 56 | |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 57 | HPLLVCO : Word32; |
| 58 | VCO_Sel : Natural range 0 .. 7; |
| 59 | begin |
| Arthur Heymans | 3f37cce | 2026-03-03 18:52:12 +0100 | [diff] [blame^] | 60 | if Config.GMCH_GM965 then |
| 61 | Registers.Read (Registers.GMCH_HPLLVCO_MOBILE, HPLLVCO); |
| 62 | VCO_Sel := Natural (HPLLVCO and 7); |
| 63 | VCO := |
| 64 | (case VCO_Sel is |
| 65 | when 0 => 3_200_000_000, |
| 66 | when 1 => 4_000_000_000, |
| 67 | when 2 => 5_333_333_333, |
| 68 | when 3 => 6_400_000_000, |
| 69 | when 4 => 3_333_333_333, |
| 70 | when 5 => 3_566_666_667, |
| 71 | when 6 => 4_266_666_667, |
| 72 | when others => 0); |
| 73 | Divisors := CL_Divs (VCO_Sel); |
| 74 | elsif Config.Has_GMCH_Mobile_VCO then |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 75 | Registers.Read (Registers.GMCH_HPLLVCO_MOBILE, HPLLVCO); |
| 76 | VCO_Sel := Natural (HPLLVCO and 7); |
| 77 | VCO := |
| 78 | (case VCO_Sel is |
| 79 | when 0 => 3_200_000_000, |
| 80 | when 1 => 4_000_000_000, |
| 81 | when 2 => 5_333_333_333, |
| 82 | --when 3 => 6_400_000_000, |
| 83 | when 4 => 2_666_666_667, |
| 84 | --when 5 => 4_266_666_667, |
| 85 | when others => 0); |
| 86 | Divisors := GM45_Divs (VCO_Sel); |
| 87 | else |
| 88 | Registers.Read (Registers.GMCH_HPLLVCO, HPLLVCO); |
| 89 | VCO_Sel := Natural (HPLLVCO and 7); |
| 90 | VCO := |
| 91 | (case VCO_Sel is |
| 92 | when 0 => 3_200_000_000, |
| 93 | when 1 => 4_000_000_000, |
| 94 | when 2 => 5_333_333_333, |
| 95 | when 3 => 4_800_000_000, |
| 96 | when others => 0); |
| 97 | Divisors := G45_Divs (VCO_Sel); |
| 98 | end if; |
| 99 | end Get_VCO; |
| 100 | |
| 101 | procedure Get_CDClk (CDClk : out Config.CDClk_Range) |
| 102 | is |
| 103 | use type HW.Word16; |
| 104 | |
| 105 | Tmp_Clk : Int64 := 0; |
| 106 | |
| 107 | VCO : Int64; |
| 108 | Divisors : Div_Array; |
| 109 | |
| 110 | GCFGC : Word16; |
| 111 | CDClk_Sel : Natural range 0 .. 7; |
| 112 | begin |
| 113 | if PCI_Usable then |
| 114 | Get_VCO (VCO, Divisors); |
| 115 | PCI_Read16 (GCFGC, 16#f0#); |
| Arthur Heymans | 3f37cce | 2026-03-03 18:52:12 +0100 | [diff] [blame^] | 116 | if Config.GMCH_GM965 then |
| 117 | -- Linux i965gm_get_cdclk: cdclk_sel = ((tmp >> 8) & 0x1f) - 1 |
| 118 | if (Shift_Right (GCFGC, 8) and 16#1f#) in 1 .. 3 then |
| 119 | CDClk_Sel := Natural (Shift_Right (GCFGC, 8) and 16#1f#) - 1; |
| 120 | else |
| 121 | CDClk_Sel := Div_Array'Last; |
| 122 | end if; |
| 123 | elsif Config.Has_GMCH_Mobile_VCO then |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 124 | CDClk_Sel := Natural (Shift_Right (GCFGC, 12) and 1); |
| 125 | else |
| 126 | CDClk_Sel := Natural (Shift_Right (GCFGC, 4) and 7); |
| 127 | end if; |
| 128 | Tmp_Clk := VCO / Divisors (CDClk_Sel); |
| 129 | end if; |
| 130 | |
| 131 | if Tmp_Clk in Config.CDClk_Range then |
| 132 | CDClk := Tmp_Clk; |
| 133 | else |
| Arthur Heymans | 3f37cce | 2026-03-03 18:52:12 +0100 | [diff] [blame^] | 134 | if Config.GMCH_GM965 then |
| 135 | CDClk := 4_000_000_000 / 20; -- 200 MHz |
| 136 | elsif Config.Has_GMCH_Mobile_VCO then |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 137 | CDClk := 5_333_333_333 / 24; |
| 138 | else |
| 139 | CDClk := 5_333_333_333 / 28; |
| 140 | end if; |
| 141 | end if; |
| 142 | end Get_CDClk; |
| 143 | |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 144 | -- The Raw Freq is 1/4 of the FSB freq |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 145 | procedure Get_Raw_Clock (Raw_Clock : out Frequency_Type) |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 146 | is |
| 147 | CLK_CFG : Word32; |
| 148 | type Freq_Sel is new Natural range 0 .. 7; |
| 149 | begin |
| 150 | Registers.Read |
| 151 | (Register => Registers.GMCH_CLKCFG, |
| 152 | Value => CLK_CFG); |
| 153 | case Freq_Sel (CLK_CFG and FSB_FREQ_SEL_MASK) is |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 154 | when 0 => Raw_Clock := CLKCFG_FSB_1067; |
| 155 | when 1 => Raw_Clock := CLKCFG_FSB_533; |
| 156 | when 2 => Raw_Clock := CLKCFG_FSB_800; |
| 157 | when 3 => Raw_Clock := CLKCFG_FSB_667; |
| 158 | when 4 => Raw_Clock := CLKCFG_FSB_1333; |
| 159 | when 5 => Raw_Clock := CLKCFG_FSB_400; |
| 160 | when 6 => Raw_Clock := CLKCFG_FSB_1067; |
| 161 | when 7 => Raw_Clock := CLKCFG_FSB_1333; |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 162 | end case; |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 163 | end Get_Raw_Clock; |
| 164 | |
| 165 | procedure Initialize |
| 166 | is |
| 167 | CDClk : Config.CDClk_Range; |
| 168 | begin |
| 169 | Get_CDClk (CDClk); |
| 170 | Config.CDClk := CDClk; |
| 171 | Config.Max_CDClk := CDClk; |
| 172 | |
| 173 | Get_Raw_Clock (Config.Raw_Clock); |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 174 | end Initialize; |
| 175 | |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame] | 176 | procedure Limit_Dotclocks |
| 177 | (Configs : in out Pipe_Configs; |
| 178 | CDClk_Switch : out Boolean) |
| 179 | is |
| 180 | begin |
| 181 | Config_Helpers.Limit_Dotclocks (Configs, Config.CDClk * 90 / 100); |
| 182 | CDClk_Switch := False; |
| 183 | end Limit_Dotclocks; |
| 184 | |
| Nico Huber | 41e8674 | 2024-07-17 17:10:28 +0200 | [diff] [blame] | 185 | procedure Power_Up (Port : Active_Port_Type; Success : out Boolean) is |
| 186 | begin |
| 187 | Success := True; |
| 188 | end Power_Up; |
| 189 | |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 190 | end HW.GFX.GMA.Power_And_Clocks; |