Serenity Operating System
at master 125 lines 4.7 kB view raw
1/* 2 * Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Format.h> 8#include <Kernel/Debug.h> 9#include <Kernel/Graphics/Intel/Transcoder/PLL.h> 10 11namespace Kernel::IntelGraphics { 12 13static constexpr PLLMaxSettings g35limits { 14 { 20'000'000, 400'000'000 }, // values in Hz, dot_clock 15 { 1'400'000'000, 2'800'000'000 }, // values in Hz, VCO 16 { 3, 8 }, // n 17 { 70, 120 }, // m 18 { 10, 20 }, // m1 19 { 5, 9 }, // m2 20 { 5, 80 }, // p 21 { 1, 8 }, // p1 22 { 5, 10 } // p2 23}; 24 25PLLMaxSettings const& pll_max_settings_for_generation(Generation generation) 26{ 27 switch (generation) { 28 case Generation::Gen4: 29 return g35limits; 30 default: 31 VERIFY_NOT_REACHED(); 32 } 33} 34 35static size_t find_absolute_difference(u64 target_frequency, u64 checked_frequency) 36{ 37 if (target_frequency >= checked_frequency) 38 return target_frequency - checked_frequency; 39 return checked_frequency - target_frequency; 40} 41 42Optional<PLLSettings> create_pll_settings(Generation generation, u64 target_frequency, u64 reference_clock) 43{ 44 PLLSettings settings {}; 45 PLLSettings best_settings {}; 46 auto& limits = pll_max_settings_for_generation(generation); 47 // FIXME: Is this correct for all Intel Native graphics cards? 48 settings.p2 = 10; 49 dbgln_if(INTEL_GRAPHICS_DEBUG, "Check PLL settings for ref clock of {} Hz, for target of {} Hz", reference_clock, target_frequency); 50 u64 best_difference = 0xffffffff; 51 for (settings.n = limits.n.min; settings.n <= limits.n.max; ++settings.n) { 52 for (settings.m1 = limits.m1.max; settings.m1 >= limits.m1.min; --settings.m1) { 53 for (settings.m2 = limits.m2.max; settings.m2 >= limits.m2.min; --settings.m2) { 54 for (settings.p1 = limits.p1.max; settings.p1 >= limits.p1.min; --settings.p1) { 55 dbgln_if(INTEL_GRAPHICS_DEBUG, "Check PLL settings for {} {} {} {} {}", settings.n, settings.m1, settings.m2, settings.p1, settings.p2); 56 if (!check_pll_settings(settings, reference_clock, limits)) 57 continue; 58 auto current_dot_clock = settings.compute_dot_clock(reference_clock); 59 if (current_dot_clock == target_frequency) 60 return settings; 61 auto difference = find_absolute_difference(target_frequency, current_dot_clock); 62 if (difference < best_difference && (current_dot_clock > target_frequency)) { 63 best_settings = settings; 64 best_difference = difference; 65 } 66 } 67 } 68 } 69 } 70 if (best_settings.is_valid()) 71 return best_settings; 72 return {}; 73} 74 75bool check_pll_settings(PLLSettings const& settings, size_t reference_clock, PLLMaxSettings const& limits) 76{ 77 if (settings.n < limits.n.min || settings.n > limits.n.max) { 78 dbgln_if(INTEL_GRAPHICS_DEBUG, "N is invalid {}", settings.n); 79 return false; 80 } 81 if (settings.m1 < limits.m1.min || settings.m1 > limits.m1.max) { 82 dbgln_if(INTEL_GRAPHICS_DEBUG, "m1 is invalid {}", settings.m1); 83 return false; 84 } 85 if (settings.m2 < limits.m2.min || settings.m2 > limits.m2.max) { 86 dbgln_if(INTEL_GRAPHICS_DEBUG, "m2 is invalid {}", settings.m2); 87 return false; 88 } 89 if (settings.p1 < limits.p1.min || settings.p1 > limits.p1.max) { 90 dbgln_if(INTEL_GRAPHICS_DEBUG, "p1 is invalid {}", settings.p1); 91 return false; 92 } 93 94 if (settings.m1 <= settings.m2) { 95 dbgln_if(INTEL_GRAPHICS_DEBUG, "m2 is invalid {} as it is bigger than m1 {}", settings.m2, settings.m1); 96 return false; 97 } 98 99 auto m = settings.compute_m(); 100 auto p = settings.compute_p(); 101 102 if (m < limits.m.min || m > limits.m.max) { 103 dbgln_if(INTEL_GRAPHICS_DEBUG, "m invalid {}", m); 104 return false; 105 } 106 if (p < limits.p.min || p > limits.p.max) { 107 dbgln_if(INTEL_GRAPHICS_DEBUG, "p invalid {}", p); 108 return false; 109 } 110 111 auto dot = settings.compute_dot_clock(reference_clock); 112 auto vco = settings.compute_vco(reference_clock); 113 114 if (dot < limits.dot_clock.min || dot > limits.dot_clock.max) { 115 dbgln_if(INTEL_GRAPHICS_DEBUG, "Dot clock invalid {}", dot); 116 return false; 117 } 118 if (vco < limits.vco.min || vco > limits.vco.max) { 119 dbgln_if(INTEL_GRAPHICS_DEBUG, "VCO clock invalid {}", vco); 120 return false; 121 } 122 return true; 123} 124 125}