| 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 | |
| 49 | HPLLVCO : Word32; |
| 50 | VCO_Sel : Natural range 0 .. 7; |
| 51 | begin |
| 52 | if Config.Has_GMCH_Mobile_VCO then |
| 53 | Registers.Read (Registers.GMCH_HPLLVCO_MOBILE, HPLLVCO); |
| 54 | VCO_Sel := Natural (HPLLVCO and 7); |
| 55 | VCO := |
| 56 | (case VCO_Sel is |
| 57 | when 0 => 3_200_000_000, |
| 58 | when 1 => 4_000_000_000, |
| 59 | when 2 => 5_333_333_333, |
| 60 | --when 3 => 6_400_000_000, |
| 61 | when 4 => 2_666_666_667, |
| 62 | --when 5 => 4_266_666_667, |
| 63 | when others => 0); |
| 64 | Divisors := GM45_Divs (VCO_Sel); |
| 65 | else |
| 66 | Registers.Read (Registers.GMCH_HPLLVCO, HPLLVCO); |
| 67 | VCO_Sel := Natural (HPLLVCO and 7); |
| 68 | VCO := |
| 69 | (case VCO_Sel is |
| 70 | when 0 => 3_200_000_000, |
| 71 | when 1 => 4_000_000_000, |
| 72 | when 2 => 5_333_333_333, |
| 73 | when 3 => 4_800_000_000, |
| 74 | when others => 0); |
| 75 | Divisors := G45_Divs (VCO_Sel); |
| 76 | end if; |
| 77 | end Get_VCO; |
| 78 | |
| 79 | procedure Get_CDClk (CDClk : out Config.CDClk_Range) |
| 80 | is |
| 81 | use type HW.Word16; |
| 82 | |
| 83 | Tmp_Clk : Int64 := 0; |
| 84 | |
| 85 | VCO : Int64; |
| 86 | Divisors : Div_Array; |
| 87 | |
| 88 | GCFGC : Word16; |
| 89 | CDClk_Sel : Natural range 0 .. 7; |
| 90 | begin |
| 91 | if PCI_Usable then |
| 92 | Get_VCO (VCO, Divisors); |
| 93 | PCI_Read16 (GCFGC, 16#f0#); |
| 94 | if Config.Has_GMCH_Mobile_VCO then |
| 95 | CDClk_Sel := Natural (Shift_Right (GCFGC, 12) and 1); |
| 96 | else |
| 97 | CDClk_Sel := Natural (Shift_Right (GCFGC, 4) and 7); |
| 98 | end if; |
| 99 | Tmp_Clk := VCO / Divisors (CDClk_Sel); |
| 100 | end if; |
| 101 | |
| 102 | if Tmp_Clk in Config.CDClk_Range then |
| 103 | CDClk := Tmp_Clk; |
| 104 | else |
| 105 | if Config.Has_GMCH_Mobile_VCO then |
| 106 | CDClk := 5_333_333_333 / 24; |
| 107 | else |
| 108 | CDClk := 5_333_333_333 / 28; |
| 109 | end if; |
| 110 | end if; |
| 111 | end Get_CDClk; |
| 112 | |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 113 | -- The Raw Freq is 1/4 of the FSB freq |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame^] | 114 | procedure Get_Raw_Clock (Raw_Clock : out Frequency_Type) |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 115 | is |
| 116 | CLK_CFG : Word32; |
| 117 | type Freq_Sel is new Natural range 0 .. 7; |
| 118 | begin |
| 119 | Registers.Read |
| 120 | (Register => Registers.GMCH_CLKCFG, |
| 121 | Value => CLK_CFG); |
| 122 | case Freq_Sel (CLK_CFG and FSB_FREQ_SEL_MASK) is |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame^] | 123 | when 0 => Raw_Clock := CLKCFG_FSB_1067; |
| 124 | when 1 => Raw_Clock := CLKCFG_FSB_533; |
| 125 | when 2 => Raw_Clock := CLKCFG_FSB_800; |
| 126 | when 3 => Raw_Clock := CLKCFG_FSB_667; |
| 127 | when 4 => Raw_Clock := CLKCFG_FSB_1333; |
| 128 | when 5 => Raw_Clock := CLKCFG_FSB_400; |
| 129 | when 6 => Raw_Clock := CLKCFG_FSB_1067; |
| 130 | when 7 => Raw_Clock := CLKCFG_FSB_1333; |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 131 | end case; |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame^] | 132 | end Get_Raw_Clock; |
| 133 | |
| 134 | procedure Initialize |
| 135 | is |
| 136 | CDClk : Config.CDClk_Range; |
| 137 | begin |
| 138 | Get_CDClk (CDClk); |
| 139 | Config.CDClk := CDClk; |
| 140 | Config.Max_CDClk := CDClk; |
| 141 | |
| 142 | Get_Raw_Clock (Config.Raw_Clock); |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 143 | end Initialize; |
| 144 | |
| Nico Huber | b47a5c4 | 2019-09-29 00:07:21 +0200 | [diff] [blame^] | 145 | procedure Limit_Dotclocks |
| 146 | (Configs : in out Pipe_Configs; |
| 147 | CDClk_Switch : out Boolean) |
| 148 | is |
| 149 | begin |
| 150 | Config_Helpers.Limit_Dotclocks (Configs, Config.CDClk * 90 / 100); |
| 151 | CDClk_Switch := False; |
| 152 | end Limit_Dotclocks; |
| 153 | |
| Arthur Heymans | 73ea032 | 2018-03-28 17:17:07 +0200 | [diff] [blame] | 154 | end HW.GFX.GMA.Power_And_Clocks; |