| Arthur Heymans | 960e239 | 2026-03-03 19:45:24 +0100 | [diff] [blame^] | 1 | -- |
| 2 | -- Copyright (C) 2026 Arthur Heymans <arthur@aheymans.xyz> |
| 3 | -- |
| 4 | -- This program is free software; you can redistribute it and/or modify |
| 5 | -- it under the terms of the GNU General Public License as published by |
| 6 | -- the Free Software Foundation; either version 2 of the License, or |
| 7 | -- (at your option) any later version. |
| 8 | -- |
| 9 | -- This program is distributed in the hope that it will be useful, |
| 10 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | -- GNU General Public License for more details. |
| 13 | -- |
| 14 | |
| 15 | with HW.GFX.GMA.Config; |
| 16 | with HW.GFX.GMA.Registers; |
| 17 | |
| 18 | package body HW.GFX.GMA.Power_And_Clocks is |
| 19 | |
| 20 | CLKCFG_FSB_MASK : constant := 7 * 2 ** 0; |
| 21 | -- hrawclk = FSB / 4. The CLKCFG FSB bits encode different FSB speeds |
| 22 | -- depending on whether the platform is mobile or desktop (ALT encoding): |
| 23 | -- mobile: 0=FSB400, 1=FSB533, 2=FSB800, 3=FSB667, 6=FSB1067, 7=FSB1333 |
| 24 | -- desktop: 0=FSB1067, 1=FSB533, 2=FSB800, 3=FSB667, 4=FSB1333, |
| 25 | -- 5=FSB400, 6=FSB1600 |
| 26 | HRAWCLK_100 : constant Frequency_Type := 100_000_000; -- FSB 400 |
| 27 | HRAWCLK_133 : constant Frequency_Type := 133_333_333; -- FSB 533 |
| 28 | HRAWCLK_167 : constant Frequency_Type := 166_666_666; -- FSB 667 |
| 29 | HRAWCLK_200 : constant Frequency_Type := 200_000_000; -- FSB 800 |
| 30 | HRAWCLK_267 : constant Frequency_Type := 266_666_667; -- FSB 1067 |
| 31 | HRAWCLK_333 : constant Frequency_Type := 333_333_333; -- FSB 1333 |
| 32 | HRAWCLK_400 : constant Frequency_Type := 400_000_000; -- FSB 1600 (desktop) |
| 33 | |
| 34 | -- i945 CDClk values (from Linux kernel intel_cdclk.c): |
| 35 | -- |
| 36 | -- i945G (desktop): fixed 400 MHz CDClk |
| 37 | -- |
| 38 | -- i945GM (mobile): read from GCFGC PCI register (0xF0) |
| 39 | -- GC_LOW_FREQUENCY_ENABLE (bit 7) => 133 MHz |
| 40 | -- GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) => 200 MHz (default) |
| 41 | -- GC_DISPLAY_CLOCK_333_320_MHZ (4 << 4) => 320 MHz |
| 42 | |
| 43 | procedure Get_CDClk (CDClk : out Config.CDClk_Range) |
| 44 | is |
| 45 | use type HW.Word16; |
| 46 | |
| 47 | GC_LOW_FREQUENCY_ENABLE : constant Word16 := 1 * 2 ** 7; |
| 48 | GC_DISPLAY_CLOCK_MASK : constant Word16 := 7 * 2 ** 4; |
| 49 | GC_DISPLAY_CLOCK_320_MHZ : constant Word16 := 4 * 2 ** 4; |
| 50 | |
| 51 | GCFGC : Word16; |
| 52 | Tmp_Clk : Frequency_Type := 200_000_000; |
| 53 | begin |
| 54 | if Config.GMCH_I945GM then |
| 55 | if PCI_Usable then |
| 56 | PCI_Read16 (GCFGC, 16#f0#); |
| 57 | if (GCFGC and GC_LOW_FREQUENCY_ENABLE) /= 0 then |
| 58 | Tmp_Clk := 133_333_333; |
| 59 | elsif (GCFGC and GC_DISPLAY_CLOCK_MASK) = GC_DISPLAY_CLOCK_320_MHZ then |
| 60 | Tmp_Clk := 320_000_000; |
| 61 | else |
| 62 | Tmp_Clk := 200_000_000; |
| 63 | end if; |
| 64 | end if; |
| 65 | else |
| 66 | -- i945G desktop: fixed 400 MHz |
| 67 | Tmp_Clk := 400_000_000; |
| 68 | end if; |
| 69 | |
| 70 | if Tmp_Clk in Config.CDClk_Range then |
| 71 | CDClk := Tmp_Clk; |
| 72 | else |
| 73 | CDClk := 200_000_000; |
| 74 | end if; |
| 75 | end Get_CDClk; |
| 76 | |
| 77 | -- hrawclk = FSB / 4. The CLKCFG FSB encoding differs between |
| 78 | -- mobile (i945GM) and desktop (i945G), see CLKCFG_FSB_MASK comment above. |
| 79 | procedure Get_Raw_Clock (Raw_Clock : out Frequency_Type) |
| 80 | is |
| 81 | CLK_CFG : Word32; |
| 82 | type Freq_Sel is new Natural range 0 .. 7; |
| 83 | begin |
| 84 | Registers.Read |
| 85 | (Register => Registers.GMCH_CLKCFG, |
| 86 | Value => CLK_CFG); |
| 87 | if Config.GMCH_I945GM then |
| 88 | Raw_Clock := (case Freq_Sel (CLK_CFG and CLKCFG_FSB_MASK) is |
| 89 | when 0 => HRAWCLK_100, -- FSB 400 |
| 90 | when 1 => HRAWCLK_133, -- FSB 533 |
| 91 | when 2 => HRAWCLK_200, -- FSB 800 |
| 92 | when 3 => HRAWCLK_167, -- FSB 667 |
| 93 | when 6 => HRAWCLK_267, -- FSB 1067 |
| 94 | when 7 => HRAWCLK_333, -- FSB 1333 |
| 95 | when others => HRAWCLK_133); |
| 96 | else |
| 97 | Raw_Clock := (case Freq_Sel (CLK_CFG and CLKCFG_FSB_MASK) is |
| 98 | when 0 => HRAWCLK_267, -- FSB 1067 |
| 99 | when 1 => HRAWCLK_133, -- FSB 533 |
| 100 | when 2 => HRAWCLK_200, -- FSB 800 |
| 101 | when 3 => HRAWCLK_167, -- FSB 667 |
| 102 | when 4 => HRAWCLK_333, -- FSB 1333 |
| 103 | when 5 => HRAWCLK_100, -- FSB 400 |
| 104 | when 6 => HRAWCLK_400, -- FSB 1600 |
| 105 | when others => HRAWCLK_133); |
| 106 | end if; |
| 107 | end Get_Raw_Clock; |
| 108 | |
| 109 | procedure Initialize |
| 110 | is |
| 111 | CDClk : Config.CDClk_Range; |
| 112 | Raw_Clk : Frequency_Type; |
| 113 | begin |
| 114 | Get_CDClk (CDClk); |
| 115 | Config.CDClk := CDClk; |
| 116 | Config.Max_CDClk := CDClk; |
| 117 | |
| 118 | Get_Raw_Clock (Raw_Clk); |
| 119 | Config.Raw_Clock := Raw_Clk; |
| 120 | end Initialize; |
| 121 | |
| 122 | procedure Limit_Dotclocks |
| 123 | (Configs : in out Pipe_Configs; |
| 124 | CDClk_Switch : out Boolean) |
| 125 | is |
| 126 | begin |
| 127 | Config_Helpers.Limit_Dotclocks (Configs, Config.CDClk * 90 / 100); |
| 128 | CDClk_Switch := False; |
| 129 | end Limit_Dotclocks; |
| 130 | |
| 131 | end HW.GFX.GMA.Power_And_Clocks; |