PLL.cpp 4.6 KB

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