mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 22:27:42 +00:00
Kernel/IntelGraphics: Move PLL handling code to a different file
Dealing with the specific details of how to program a PLL should be done in a separate file to ensure we can easily expand it to support future generations of the Intel graphics device.
This commit is contained in:
parent
9eab59c42b
commit
ac4829cc50
5 changed files with 146 additions and 107 deletions
|
@ -80,6 +80,7 @@ set(KERNEL_SOURCES
|
||||||
Graphics/Intel/Plane/G33DisplayPlane.cpp
|
Graphics/Intel/Plane/G33DisplayPlane.cpp
|
||||||
Graphics/Intel/Transcoder/AnalogDisplayTranscoder.cpp
|
Graphics/Intel/Transcoder/AnalogDisplayTranscoder.cpp
|
||||||
Graphics/Intel/Transcoder/DisplayTranscoder.cpp
|
Graphics/Intel/Transcoder/DisplayTranscoder.cpp
|
||||||
|
Graphics/Intel/Transcoder/PLL.cpp
|
||||||
Graphics/Intel/DisplayConnectorGroup.cpp
|
Graphics/Intel/DisplayConnectorGroup.cpp
|
||||||
Graphics/Intel/NativeDisplayConnector.cpp
|
Graphics/Intel/NativeDisplayConnector.cpp
|
||||||
Graphics/Intel/NativeGraphicsAdapter.cpp
|
Graphics/Intel/NativeGraphicsAdapter.cpp
|
||||||
|
|
|
@ -13,115 +13,12 @@
|
||||||
#include <Kernel/Graphics/Intel/DisplayConnectorGroup.h>
|
#include <Kernel/Graphics/Intel/DisplayConnectorGroup.h>
|
||||||
#include <Kernel/Graphics/Intel/Plane/G33DisplayPlane.h>
|
#include <Kernel/Graphics/Intel/Plane/G33DisplayPlane.h>
|
||||||
#include <Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.h>
|
#include <Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.h>
|
||||||
|
#include <Kernel/Graphics/Intel/Transcoder/PLL.h>
|
||||||
#include <Kernel/Memory/Region.h>
|
#include <Kernel/Memory/Region.h>
|
||||||
#include <Kernel/Memory/TypedMapping.h>
|
#include <Kernel/Memory/TypedMapping.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
namespace IntelGraphics {
|
|
||||||
|
|
||||||
static constexpr PLLMaxSettings G35Limits {
|
|
||||||
{ 20'000'000, 400'000'000 }, // values in Hz, dot_clock
|
|
||||||
{ 1'400'000'000, 2'800'000'000 }, // values in Hz, VCO
|
|
||||||
{ 3, 8 }, // n
|
|
||||||
{ 70, 120 }, // m
|
|
||||||
{ 10, 20 }, // m1
|
|
||||||
{ 5, 9 }, // m2
|
|
||||||
{ 5, 80 }, // p
|
|
||||||
{ 1, 8 }, // p1
|
|
||||||
{ 5, 10 } // p2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool check_pll_settings(IntelGraphics::PLLSettings const& settings, size_t reference_clock, IntelGraphics::PLLMaxSettings const& limits)
|
|
||||||
{
|
|
||||||
if (settings.n < limits.n.min || settings.n > limits.n.max) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "N is invalid {}", settings.n);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (settings.m1 < limits.m1.min || settings.m1 > limits.m1.max) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "m1 is invalid {}", settings.m1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (settings.m2 < limits.m2.min || settings.m2 > limits.m2.max) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "m2 is invalid {}", settings.m2);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (settings.p1 < limits.p1.min || settings.p1 > limits.p1.max) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "p1 is invalid {}", settings.p1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings.m1 <= settings.m2) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "m2 is invalid {} as it is bigger than m1 {}", settings.m2, settings.m1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto m = settings.compute_m();
|
|
||||||
auto p = settings.compute_p();
|
|
||||||
|
|
||||||
if (m < limits.m.min || m > limits.m.max) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "m invalid {}", m);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (p < limits.p.min || p > limits.p.max) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "p invalid {}", p);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dot = settings.compute_dot_clock(reference_clock);
|
|
||||||
auto vco = settings.compute_vco(reference_clock);
|
|
||||||
|
|
||||||
if (dot < limits.dot_clock.min || dot > limits.dot_clock.max) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "Dot clock invalid {}", dot);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (vco < limits.vco.min || vco > limits.vco.max) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "VCO clock invalid {}", vco);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t find_absolute_difference(u64 target_frequency, u64 checked_frequency)
|
|
||||||
{
|
|
||||||
if (target_frequency >= checked_frequency)
|
|
||||||
return target_frequency - checked_frequency;
|
|
||||||
return checked_frequency - target_frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<IntelGraphics::PLLSettings> IntelDisplayConnectorGroup::create_pll_settings(u64 target_frequency, u64 reference_clock, IntelGraphics::PLLMaxSettings const& limits)
|
|
||||||
{
|
|
||||||
IntelGraphics::PLLSettings settings;
|
|
||||||
IntelGraphics::PLLSettings best_settings;
|
|
||||||
// FIXME: Is this correct for all Intel Native graphics cards?
|
|
||||||
settings.p2 = 10;
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "Check PLL settings for ref clock of {} Hz, for target of {} Hz", reference_clock, target_frequency);
|
|
||||||
u64 best_difference = 0xffffffff;
|
|
||||||
for (settings.n = limits.n.min; settings.n <= limits.n.max; ++settings.n) {
|
|
||||||
for (settings.m1 = limits.m1.max; settings.m1 >= limits.m1.min; --settings.m1) {
|
|
||||||
for (settings.m2 = limits.m2.max; settings.m2 >= limits.m2.min; --settings.m2) {
|
|
||||||
for (settings.p1 = limits.p1.max; settings.p1 >= limits.p1.min; --settings.p1) {
|
|
||||||
dbgln_if(INTEL_GRAPHICS_DEBUG, "Check PLL settings for {} {} {} {} {}", settings.n, settings.m1, settings.m2, settings.p1, settings.p2);
|
|
||||||
if (!check_pll_settings(settings, reference_clock, limits))
|
|
||||||
continue;
|
|
||||||
auto current_dot_clock = settings.compute_dot_clock(reference_clock);
|
|
||||||
if (current_dot_clock == target_frequency)
|
|
||||||
return settings;
|
|
||||||
auto difference = find_absolute_difference(target_frequency, current_dot_clock);
|
|
||||||
if (difference < best_difference && (current_dot_clock > target_frequency)) {
|
|
||||||
best_settings = settings;
|
|
||||||
best_difference = difference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (best_settings.is_valid())
|
|
||||||
return best_settings;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<NonnullLockRefPtr<IntelDisplayConnectorGroup>> IntelDisplayConnectorGroup::try_create(Badge<IntelNativeGraphicsAdapter>, IntelGraphics::Generation generation, MMIORegion const& first_region, MMIORegion const& second_region)
|
ErrorOr<NonnullLockRefPtr<IntelDisplayConnectorGroup>> IntelDisplayConnectorGroup::try_create(Badge<IntelNativeGraphicsAdapter>, IntelGraphics::Generation generation, MMIORegion const& first_region, MMIORegion const& second_region)
|
||||||
{
|
{
|
||||||
auto registers_region = TRY(MM.allocate_kernel_region(first_region.pci_bar_paddr, first_region.pci_bar_space_length, "Intel Native Graphics Registers"sv, Memory::Region::Access::ReadWrite));
|
auto registers_region = TRY(MM.allocate_kernel_region(first_region.pci_bar_paddr, first_region.pci_bar_space_length, "Intel Native Graphics Registers"sv, Memory::Region::Access::ReadWrite));
|
||||||
|
@ -323,7 +220,7 @@ bool IntelDisplayConnectorGroup::set_crt_resolution(DisplayConnector::ModeSettin
|
||||||
GraphicsManagement::the().disable_vga_emulation_access_permanently();
|
GraphicsManagement::the().disable_vga_emulation_access_permanently();
|
||||||
|
|
||||||
auto dac_multiplier = compute_dac_multiplier(mode_setting.pixel_clock_in_khz);
|
auto dac_multiplier = compute_dac_multiplier(mode_setting.pixel_clock_in_khz);
|
||||||
auto pll_settings = create_pll_settings((1000 * mode_setting.pixel_clock_in_khz * dac_multiplier), 96'000'000, IntelGraphics::G35Limits);
|
auto pll_settings = create_pll_settings(m_generation, (1000 * mode_setting.pixel_clock_in_khz * dac_multiplier), 96'000'000);
|
||||||
if (!pll_settings.has_value())
|
if (!pll_settings.has_value())
|
||||||
return false;
|
return false;
|
||||||
auto settings = pll_settings.value();
|
auto settings = pll_settings.value();
|
||||||
|
|
|
@ -75,8 +75,6 @@ private:
|
||||||
void disable_dac_output();
|
void disable_dac_output();
|
||||||
void enable_dac_output();
|
void enable_dac_output();
|
||||||
|
|
||||||
Optional<IntelGraphics::PLLSettings> create_pll_settings(u64 target_frequency, u64 reference_clock, IntelGraphics::PLLMaxSettings const&);
|
|
||||||
|
|
||||||
Spinlock<LockRank::None> m_control_lock;
|
Spinlock<LockRank::None> m_control_lock;
|
||||||
Spinlock<LockRank::None> m_modeset_lock;
|
Spinlock<LockRank::None> m_modeset_lock;
|
||||||
mutable Spinlock<LockRank::None> m_registers_lock;
|
mutable Spinlock<LockRank::None> m_registers_lock;
|
||||||
|
|
125
Kernel/Graphics/Intel/Transcoder/PLL.cpp
Normal file
125
Kernel/Graphics/Intel/Transcoder/PLL.cpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/Format.h>
|
||||||
|
#include <Kernel/Debug.h>
|
||||||
|
#include <Kernel/Graphics/Intel/Transcoder/PLL.h>
|
||||||
|
|
||||||
|
namespace Kernel::IntelGraphics {
|
||||||
|
|
||||||
|
static constexpr PLLMaxSettings g35limits {
|
||||||
|
{ 20'000'000, 400'000'000 }, // values in Hz, dot_clock
|
||||||
|
{ 1'400'000'000, 2'800'000'000 }, // values in Hz, VCO
|
||||||
|
{ 3, 8 }, // n
|
||||||
|
{ 70, 120 }, // m
|
||||||
|
{ 10, 20 }, // m1
|
||||||
|
{ 5, 9 }, // m2
|
||||||
|
{ 5, 80 }, // p
|
||||||
|
{ 1, 8 }, // p1
|
||||||
|
{ 5, 10 } // p2
|
||||||
|
};
|
||||||
|
|
||||||
|
PLLMaxSettings const& pll_max_settings_for_generation(Generation generation)
|
||||||
|
{
|
||||||
|
switch (generation) {
|
||||||
|
case Generation::Gen4:
|
||||||
|
return g35limits;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t find_absolute_difference(u64 target_frequency, u64 checked_frequency)
|
||||||
|
{
|
||||||
|
if (target_frequency >= checked_frequency)
|
||||||
|
return target_frequency - checked_frequency;
|
||||||
|
return checked_frequency - target_frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<PLLSettings> create_pll_settings(Generation generation, u64 target_frequency, u64 reference_clock)
|
||||||
|
{
|
||||||
|
PLLSettings settings {};
|
||||||
|
PLLSettings best_settings {};
|
||||||
|
auto& limits = pll_max_settings_for_generation(generation);
|
||||||
|
// FIXME: Is this correct for all Intel Native graphics cards?
|
||||||
|
settings.p2 = 10;
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "Check PLL settings for ref clock of {} Hz, for target of {} Hz", reference_clock, target_frequency);
|
||||||
|
u64 best_difference = 0xffffffff;
|
||||||
|
for (settings.n = limits.n.min; settings.n <= limits.n.max; ++settings.n) {
|
||||||
|
for (settings.m1 = limits.m1.max; settings.m1 >= limits.m1.min; --settings.m1) {
|
||||||
|
for (settings.m2 = limits.m2.max; settings.m2 >= limits.m2.min; --settings.m2) {
|
||||||
|
for (settings.p1 = limits.p1.max; settings.p1 >= limits.p1.min; --settings.p1) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "Check PLL settings for {} {} {} {} {}", settings.n, settings.m1, settings.m2, settings.p1, settings.p2);
|
||||||
|
if (!check_pll_settings(settings, reference_clock, limits))
|
||||||
|
continue;
|
||||||
|
auto current_dot_clock = settings.compute_dot_clock(reference_clock);
|
||||||
|
if (current_dot_clock == target_frequency)
|
||||||
|
return settings;
|
||||||
|
auto difference = find_absolute_difference(target_frequency, current_dot_clock);
|
||||||
|
if (difference < best_difference && (current_dot_clock > target_frequency)) {
|
||||||
|
best_settings = settings;
|
||||||
|
best_difference = difference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best_settings.is_valid())
|
||||||
|
return best_settings;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_pll_settings(PLLSettings const& settings, size_t reference_clock, PLLMaxSettings const& limits)
|
||||||
|
{
|
||||||
|
if (settings.n < limits.n.min || settings.n > limits.n.max) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "N is invalid {}", settings.n);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (settings.m1 < limits.m1.min || settings.m1 > limits.m1.max) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "m1 is invalid {}", settings.m1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (settings.m2 < limits.m2.min || settings.m2 > limits.m2.max) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "m2 is invalid {}", settings.m2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (settings.p1 < limits.p1.min || settings.p1 > limits.p1.max) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "p1 is invalid {}", settings.p1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.m1 <= settings.m2) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "m2 is invalid {} as it is bigger than m1 {}", settings.m2, settings.m1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto m = settings.compute_m();
|
||||||
|
auto p = settings.compute_p();
|
||||||
|
|
||||||
|
if (m < limits.m.min || m > limits.m.max) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "m invalid {}", m);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (p < limits.p.min || p > limits.p.max) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "p invalid {}", p);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dot = settings.compute_dot_clock(reference_clock);
|
||||||
|
auto vco = settings.compute_vco(reference_clock);
|
||||||
|
|
||||||
|
if (dot < limits.dot_clock.min || dot > limits.dot_clock.max) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "Dot clock invalid {}", dot);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (vco < limits.vco.min || vco > limits.vco.max) {
|
||||||
|
dbgln_if(INTEL_GRAPHICS_DEBUG, "VCO clock invalid {}", vco);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
Kernel/Graphics/Intel/Transcoder/PLL.h
Normal file
18
Kernel/Graphics/Intel/Transcoder/PLL.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Optional.h>
|
||||||
|
#include <Kernel/Graphics/Intel/Definitions.h>
|
||||||
|
|
||||||
|
namespace Kernel::IntelGraphics {
|
||||||
|
|
||||||
|
PLLMaxSettings const& pll_max_settings_for_generation(Generation);
|
||||||
|
Optional<PLLSettings> create_pll_settings(Generation, u64 target_frequency, u64 reference_clock);
|
||||||
|
bool check_pll_settings(PLLSettings const& settings, size_t reference_clock, PLLMaxSettings const& limits);
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue