| -- |
| -- Copyright (C) 2026 Arthur Heymans <arthur@aheymans.xyz> |
| -- |
| -- This program is free software; you can redistribute it and/or modify |
| -- it under the terms of the GNU General Public License as published by |
| -- the Free Software Foundation; either version 2 of the License, or |
| -- (at your option) any later version. |
| -- |
| -- This program is distributed in the hope that it will be useful, |
| -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
| -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| -- GNU General Public License for more details. |
| -- |
| |
| with HW.GFX.GMA.Config; |
| with HW.GFX.GMA.Registers; |
| |
| package body HW.GFX.GMA.Power_And_Clocks is |
| |
| CLKCFG_FSB_MASK : constant := 7 * 2 ** 0; |
| -- hrawclk = FSB / 4. The CLKCFG FSB bits encode different FSB speeds |
| -- depending on whether the platform is mobile or desktop (ALT encoding): |
| -- mobile: 0=FSB400, 1=FSB533, 2=FSB800, 3=FSB667, 6=FSB1067, 7=FSB1333 |
| -- desktop: 0=FSB1067, 1=FSB533, 2=FSB800, 3=FSB667, 4=FSB1333, |
| -- 5=FSB400, 6=FSB1600 |
| HRAWCLK_100 : constant Frequency_Type := 100_000_000; -- FSB 400 |
| HRAWCLK_133 : constant Frequency_Type := 133_333_333; -- FSB 533 |
| HRAWCLK_167 : constant Frequency_Type := 166_666_666; -- FSB 667 |
| HRAWCLK_200 : constant Frequency_Type := 200_000_000; -- FSB 800 |
| HRAWCLK_267 : constant Frequency_Type := 266_666_667; -- FSB 1067 |
| HRAWCLK_333 : constant Frequency_Type := 333_333_333; -- FSB 1333 |
| HRAWCLK_400 : constant Frequency_Type := 400_000_000; -- FSB 1600 (desktop) |
| |
| -- i945 CDClk values (from Linux kernel intel_cdclk.c): |
| -- |
| -- i945G (desktop): fixed 400 MHz CDClk |
| -- |
| -- i945GM (mobile): read from GCFGC PCI register (0xF0) |
| -- GC_LOW_FREQUENCY_ENABLE (bit 7) => 133 MHz |
| -- GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) => 200 MHz (default) |
| -- GC_DISPLAY_CLOCK_333_320_MHZ (4 << 4) => 320 MHz |
| |
| procedure Get_CDClk (CDClk : out Config.CDClk_Range) |
| is |
| use type HW.Word16; |
| |
| GC_LOW_FREQUENCY_ENABLE : constant Word16 := 1 * 2 ** 7; |
| GC_DISPLAY_CLOCK_MASK : constant Word16 := 7 * 2 ** 4; |
| GC_DISPLAY_CLOCK_320_MHZ : constant Word16 := 4 * 2 ** 4; |
| |
| GCFGC : Word16; |
| Tmp_Clk : Frequency_Type := 200_000_000; |
| begin |
| if Config.GMCH_I945GM then |
| if PCI_Usable then |
| PCI_Read16 (GCFGC, 16#f0#); |
| if (GCFGC and GC_LOW_FREQUENCY_ENABLE) /= 0 then |
| Tmp_Clk := 133_333_333; |
| elsif (GCFGC and GC_DISPLAY_CLOCK_MASK) = GC_DISPLAY_CLOCK_320_MHZ then |
| Tmp_Clk := 320_000_000; |
| else |
| Tmp_Clk := 200_000_000; |
| end if; |
| end if; |
| else |
| -- i945G desktop: fixed 400 MHz |
| Tmp_Clk := 400_000_000; |
| end if; |
| |
| if Tmp_Clk in Config.CDClk_Range then |
| CDClk := Tmp_Clk; |
| else |
| CDClk := 200_000_000; |
| end if; |
| end Get_CDClk; |
| |
| -- hrawclk = FSB / 4. The CLKCFG FSB encoding differs between |
| -- mobile (i945GM) and desktop (i945G), see CLKCFG_FSB_MASK comment above. |
| procedure Get_Raw_Clock (Raw_Clock : out Frequency_Type) |
| is |
| CLK_CFG : Word32; |
| type Freq_Sel is new Natural range 0 .. 7; |
| begin |
| Registers.Read |
| (Register => Registers.GMCH_CLKCFG, |
| Value => CLK_CFG); |
| if Config.GMCH_I945GM then |
| Raw_Clock := (case Freq_Sel (CLK_CFG and CLKCFG_FSB_MASK) is |
| when 0 => HRAWCLK_100, -- FSB 400 |
| when 1 => HRAWCLK_133, -- FSB 533 |
| when 2 => HRAWCLK_200, -- FSB 800 |
| when 3 => HRAWCLK_167, -- FSB 667 |
| when 6 => HRAWCLK_267, -- FSB 1067 |
| when 7 => HRAWCLK_333, -- FSB 1333 |
| when others => HRAWCLK_133); |
| else |
| Raw_Clock := (case Freq_Sel (CLK_CFG and CLKCFG_FSB_MASK) is |
| when 0 => HRAWCLK_267, -- FSB 1067 |
| when 1 => HRAWCLK_133, -- FSB 533 |
| when 2 => HRAWCLK_200, -- FSB 800 |
| when 3 => HRAWCLK_167, -- FSB 667 |
| when 4 => HRAWCLK_333, -- FSB 1333 |
| when 5 => HRAWCLK_100, -- FSB 400 |
| when 6 => HRAWCLK_400, -- FSB 1600 |
| when others => HRAWCLK_133); |
| end if; |
| end Get_Raw_Clock; |
| |
| procedure Initialize |
| is |
| CDClk : Config.CDClk_Range; |
| Raw_Clk : Frequency_Type; |
| begin |
| Get_CDClk (CDClk); |
| Config.CDClk := CDClk; |
| Config.Max_CDClk := CDClk; |
| |
| Get_Raw_Clock (Raw_Clk); |
| Config.Raw_Clock := Raw_Clk; |
| end Initialize; |
| |
| procedure Limit_Dotclocks |
| (Configs : in out Pipe_Configs; |
| CDClk_Switch : out Boolean) |
| is |
| begin |
| Config_Helpers.Limit_Dotclocks (Configs, Config.CDClk * 90 / 100); |
| CDClk_Switch := False; |
| end Limit_Dotclocks; |
| |
| procedure Power_Up (Port : Active_Port_Type; Success : out Boolean) is |
| begin |
| Success := True; |
| end Power_Up; |
| |
| end HW.GFX.GMA.Power_And_Clocks; |