NativeDisplayConnector.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. /*
  2. * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Arch/Delay.h>
  7. #include <Kernel/Bus/PCI/API.h>
  8. #include <Kernel/Debug.h>
  9. #include <Kernel/Devices/DeviceManagement.h>
  10. #include <Kernel/Graphics/Console/ContiguousFramebufferConsole.h>
  11. #include <Kernel/Graphics/GraphicsManagement.h>
  12. #include <Kernel/Graphics/Intel/NativeDisplayConnector.h>
  13. #include <Kernel/Memory/Region.h>
  14. namespace Kernel {
  15. namespace IntelGraphics {
  16. #define DDC2_I2C_ADDRESS 0x50
  17. struct PLLSettings {
  18. bool is_valid() const { return (n != 0 && m1 != 0 && m2 != 0 && p1 != 0 && p2 != 0); }
  19. u64 compute_dot_clock(u64 refclock) const
  20. {
  21. return (refclock * (5 * m1 + m2) / n) / (p1 * p2);
  22. }
  23. u64 compute_vco(u64 refclock) const
  24. {
  25. return refclock * (5 * m1 + m2) / n;
  26. }
  27. u64 compute_m() const
  28. {
  29. return 5 * m1 + m2;
  30. }
  31. u64 compute_p() const
  32. {
  33. return p1 * p2;
  34. }
  35. u64 n { 0 };
  36. u64 m1 { 0 };
  37. u64 m2 { 0 };
  38. u64 p1 { 0 };
  39. u64 p2 { 0 };
  40. };
  41. static constexpr PLLMaxSettings G35Limits {
  42. { 20'000'000, 400'000'000 }, // values in Hz, dot_clock
  43. { 1'400'000'000, 2'800'000'000 }, // values in Hz, VCO
  44. { 3, 8 }, // n
  45. { 70, 120 }, // m
  46. { 10, 20 }, // m1
  47. { 5, 9 }, // m2
  48. { 5, 80 }, // p
  49. { 1, 8 }, // p1
  50. { 5, 10 } // p2
  51. };
  52. }
  53. static Graphics::Modesetting calculate_modesetting_from_edid(EDID::Parser& edid, size_t index)
  54. {
  55. auto details = edid.detailed_timing(index).release_value();
  56. Graphics::Modesetting mode;
  57. VERIFY(details.pixel_clock_khz());
  58. mode.pixel_clock_in_khz = details.pixel_clock_khz();
  59. size_t horizontal_active = details.horizontal_addressable_pixels();
  60. size_t horizontal_sync_offset = details.horizontal_front_porch_pixels();
  61. mode.horizontal.active = horizontal_active;
  62. mode.horizontal.sync_start = horizontal_active + horizontal_sync_offset;
  63. mode.horizontal.sync_end = horizontal_active + horizontal_sync_offset + details.horizontal_sync_pulse_width_pixels();
  64. mode.horizontal.total = horizontal_active + details.horizontal_blanking_pixels();
  65. size_t vertical_active = details.vertical_addressable_lines();
  66. size_t vertical_sync_offset = details.vertical_front_porch_lines();
  67. mode.vertical.active = vertical_active;
  68. mode.vertical.sync_start = vertical_active + vertical_sync_offset;
  69. mode.vertical.sync_end = vertical_active + vertical_sync_offset + details.vertical_sync_pulse_width_lines();
  70. mode.vertical.total = vertical_active + details.vertical_blanking_lines();
  71. return mode;
  72. }
  73. static bool check_pll_settings(IntelGraphics::PLLSettings const& settings, size_t reference_clock, IntelGraphics::PLLMaxSettings const& limits)
  74. {
  75. if (settings.n < limits.n.min || settings.n > limits.n.max) {
  76. dbgln_if(INTEL_GRAPHICS_DEBUG, "N is invalid {}", settings.n);
  77. return false;
  78. }
  79. if (settings.m1 < limits.m1.min || settings.m1 > limits.m1.max) {
  80. dbgln_if(INTEL_GRAPHICS_DEBUG, "m1 is invalid {}", settings.m1);
  81. return false;
  82. }
  83. if (settings.m2 < limits.m2.min || settings.m2 > limits.m2.max) {
  84. dbgln_if(INTEL_GRAPHICS_DEBUG, "m2 is invalid {}", settings.m2);
  85. return false;
  86. }
  87. if (settings.p1 < limits.p1.min || settings.p1 > limits.p1.max) {
  88. dbgln_if(INTEL_GRAPHICS_DEBUG, "p1 is invalid {}", settings.p1);
  89. return false;
  90. }
  91. if (settings.m1 <= settings.m2) {
  92. dbgln_if(INTEL_GRAPHICS_DEBUG, "m2 is invalid {} as it is bigger than m1 {}", settings.m2, settings.m1);
  93. return false;
  94. }
  95. auto m = settings.compute_m();
  96. auto p = settings.compute_p();
  97. if (m < limits.m.min || m > limits.m.max) {
  98. dbgln_if(INTEL_GRAPHICS_DEBUG, "m invalid {}", m);
  99. return false;
  100. }
  101. if (p < limits.p.min || p > limits.p.max) {
  102. dbgln_if(INTEL_GRAPHICS_DEBUG, "p invalid {}", p);
  103. return false;
  104. }
  105. auto dot = settings.compute_dot_clock(reference_clock);
  106. auto vco = settings.compute_vco(reference_clock);
  107. if (dot < limits.dot_clock.min || dot > limits.dot_clock.max) {
  108. dbgln_if(INTEL_GRAPHICS_DEBUG, "Dot clock invalid {}", dot);
  109. return false;
  110. }
  111. if (vco < limits.vco.min || vco > limits.vco.max) {
  112. dbgln_if(INTEL_GRAPHICS_DEBUG, "VCO clock invalid {}", vco);
  113. return false;
  114. }
  115. return true;
  116. }
  117. static size_t find_absolute_difference(u64 target_frequency, u64 checked_frequency)
  118. {
  119. if (target_frequency >= checked_frequency)
  120. return target_frequency - checked_frequency;
  121. return checked_frequency - target_frequency;
  122. }
  123. Optional<IntelGraphics::PLLSettings> IntelNativeDisplayConnector::create_pll_settings(u64 target_frequency, u64 reference_clock, IntelGraphics::PLLMaxSettings const& limits)
  124. {
  125. IntelGraphics::PLLSettings settings;
  126. IntelGraphics::PLLSettings best_settings;
  127. // FIXME: Is this correct for all Intel Native graphics cards?
  128. settings.p2 = 10;
  129. dbgln_if(INTEL_GRAPHICS_DEBUG, "Check PLL settings for ref clock of {} Hz, for target of {} Hz", reference_clock, target_frequency);
  130. u64 best_difference = 0xffffffff;
  131. for (settings.n = limits.n.min; settings.n <= limits.n.max; ++settings.n) {
  132. for (settings.m1 = limits.m1.max; settings.m1 >= limits.m1.min; --settings.m1) {
  133. for (settings.m2 = limits.m2.max; settings.m2 >= limits.m2.min; --settings.m2) {
  134. for (settings.p1 = limits.p1.max; settings.p1 >= limits.p1.min; --settings.p1) {
  135. dbgln_if(INTEL_GRAPHICS_DEBUG, "Check PLL settings for {} {} {} {} {}", settings.n, settings.m1, settings.m2, settings.p1, settings.p2);
  136. if (!check_pll_settings(settings, reference_clock, limits))
  137. continue;
  138. auto current_dot_clock = settings.compute_dot_clock(reference_clock);
  139. if (current_dot_clock == target_frequency)
  140. return settings;
  141. auto difference = find_absolute_difference(target_frequency, current_dot_clock);
  142. if (difference < best_difference && (current_dot_clock > target_frequency)) {
  143. best_settings = settings;
  144. best_difference = difference;
  145. }
  146. }
  147. }
  148. }
  149. }
  150. if (best_settings.is_valid())
  151. return best_settings;
  152. return {};
  153. }
  154. ErrorOr<NonnullLockRefPtr<IntelNativeDisplayConnector>> IntelNativeDisplayConnector::try_create(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, PhysicalAddress registers_region_address, size_t registers_region_length)
  155. {
  156. auto registers_region = TRY(MM.allocate_kernel_region(PhysicalAddress(registers_region_address), registers_region_length, "Intel Native Graphics Registers"sv, Memory::Region::Access::ReadWrite));
  157. auto connector = TRY(DeviceManagement::try_create_device<IntelNativeDisplayConnector>(framebuffer_address, framebuffer_resource_size, move(registers_region)));
  158. TRY(connector->initialize_gmbus_settings_and_read_edid());
  159. // Note: This is very important to set the resolution to something safe so we
  160. // can create a framebuffer console with valid resolution.
  161. {
  162. SpinlockLocker control_lock(connector->m_control_lock);
  163. TRY(connector->set_safe_mode_setting());
  164. }
  165. TRY(connector->create_attached_framebuffer_console());
  166. return connector;
  167. }
  168. ErrorOr<void> IntelNativeDisplayConnector::initialize_gmbus_settings_and_read_edid()
  169. {
  170. gmbus_read_edid();
  171. return {};
  172. }
  173. ErrorOr<void> IntelNativeDisplayConnector::set_y_offset(size_t)
  174. {
  175. return Error::from_errno(ENOTIMPL);
  176. }
  177. ErrorOr<void> IntelNativeDisplayConnector::unblank()
  178. {
  179. return Error::from_errno(ENOTIMPL);
  180. }
  181. void IntelNativeDisplayConnector::enable_console()
  182. {
  183. VERIFY(m_control_lock.is_locked());
  184. VERIFY(m_framebuffer_console);
  185. m_framebuffer_console->enable();
  186. }
  187. void IntelNativeDisplayConnector::disable_console()
  188. {
  189. VERIFY(m_control_lock.is_locked());
  190. VERIFY(m_framebuffer_console);
  191. m_framebuffer_console->disable();
  192. }
  193. ErrorOr<void> IntelNativeDisplayConnector::flush_first_surface()
  194. {
  195. return Error::from_errno(ENOTSUP);
  196. }
  197. ErrorOr<void> IntelNativeDisplayConnector::create_attached_framebuffer_console()
  198. {
  199. m_framebuffer_console = Graphics::ContiguousFramebufferConsole::initialize(m_framebuffer_address.value(), m_current_mode_setting.horizontal_active, m_current_mode_setting.vertical_active, m_current_mode_setting.horizontal_stride);
  200. GraphicsManagement::the().set_console(*m_framebuffer_console);
  201. return {};
  202. }
  203. IntelNativeDisplayConnector::IntelNativeDisplayConnector(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, NonnullOwnPtr<Memory::Region> registers_region)
  204. : DisplayConnector(framebuffer_address, framebuffer_resource_size, true)
  205. , m_registers_region(move(registers_region))
  206. {
  207. {
  208. SpinlockLocker control_lock(m_control_lock);
  209. set_gmbus_default_rate();
  210. set_gmbus_pin_pair(IntelGraphics::GMBusPinPair::DedicatedAnalog);
  211. }
  212. }
  213. ErrorOr<void> IntelNativeDisplayConnector::set_mode_setting(DisplayConnector::ModeSetting const&)
  214. {
  215. return Error::from_errno(ENOTIMPL);
  216. }
  217. ErrorOr<void> IntelNativeDisplayConnector::set_safe_mode_setting()
  218. {
  219. set_safe_crt_resolution();
  220. return {};
  221. }
  222. void IntelNativeDisplayConnector::enable_vga_plane()
  223. {
  224. VERIFY(m_control_lock.is_locked());
  225. VERIFY(m_modeset_lock.is_locked());
  226. }
  227. [[maybe_unused]] static StringView convert_register_index_to_string(IntelGraphics::RegisterIndex index)
  228. {
  229. switch (index) {
  230. case IntelGraphics::RegisterIndex::PipeAConf:
  231. return "PipeAConf"sv;
  232. case IntelGraphics::RegisterIndex::PipeBConf:
  233. return "PipeBConf"sv;
  234. case IntelGraphics::RegisterIndex::GMBusData:
  235. return "GMBusData"sv;
  236. case IntelGraphics::RegisterIndex::GMBusStatus:
  237. return "GMBusStatus"sv;
  238. case IntelGraphics::RegisterIndex::GMBusCommand:
  239. return "GMBusCommand"sv;
  240. case IntelGraphics::RegisterIndex::GMBusClock:
  241. return "GMBusClock"sv;
  242. case IntelGraphics::RegisterIndex::DisplayPlaneAControl:
  243. return "DisplayPlaneAControl"sv;
  244. case IntelGraphics::RegisterIndex::DisplayPlaneALinearOffset:
  245. return "DisplayPlaneALinearOffset"sv;
  246. case IntelGraphics::RegisterIndex::DisplayPlaneAStride:
  247. return "DisplayPlaneAStride"sv;
  248. case IntelGraphics::RegisterIndex::DisplayPlaneASurface:
  249. return "DisplayPlaneASurface"sv;
  250. case IntelGraphics::RegisterIndex::DPLLDivisorA0:
  251. return "DPLLDivisorA0"sv;
  252. case IntelGraphics::RegisterIndex::DPLLDivisorA1:
  253. return "DPLLDivisorA1"sv;
  254. case IntelGraphics::RegisterIndex::DPLLControlA:
  255. return "DPLLControlA"sv;
  256. case IntelGraphics::RegisterIndex::DPLLControlB:
  257. return "DPLLControlB"sv;
  258. case IntelGraphics::RegisterIndex::DPLLMultiplierA:
  259. return "DPLLMultiplierA"sv;
  260. case IntelGraphics::RegisterIndex::HTotalA:
  261. return "HTotalA"sv;
  262. case IntelGraphics::RegisterIndex::HBlankA:
  263. return "HBlankA"sv;
  264. case IntelGraphics::RegisterIndex::HSyncA:
  265. return "HSyncA"sv;
  266. case IntelGraphics::RegisterIndex::VTotalA:
  267. return "VTotalA"sv;
  268. case IntelGraphics::RegisterIndex::VBlankA:
  269. return "VBlankA"sv;
  270. case IntelGraphics::RegisterIndex::VSyncA:
  271. return "VSyncA"sv;
  272. case IntelGraphics::RegisterIndex::PipeASource:
  273. return "PipeASource"sv;
  274. case IntelGraphics::RegisterIndex::AnalogDisplayPort:
  275. return "AnalogDisplayPort"sv;
  276. case IntelGraphics::RegisterIndex::VGADisplayPlaneControl:
  277. return "VGADisplayPlaneControl"sv;
  278. default:
  279. VERIFY_NOT_REACHED();
  280. }
  281. }
  282. void IntelNativeDisplayConnector::write_to_register(IntelGraphics::RegisterIndex index, u32 value) const
  283. {
  284. VERIFY(m_control_lock.is_locked());
  285. SpinlockLocker lock(m_registers_lock);
  286. dbgln_if(INTEL_GRAPHICS_DEBUG, "Intel Graphics Display Connector:: Write to {} value of {:x}", convert_register_index_to_string(index), value);
  287. auto* reg = (u32 volatile*)m_registers_region->vaddr().offset(to_underlying(index)).as_ptr();
  288. *reg = value;
  289. }
  290. u32 IntelNativeDisplayConnector::read_from_register(IntelGraphics::RegisterIndex index) const
  291. {
  292. VERIFY(m_control_lock.is_locked());
  293. SpinlockLocker lock(m_registers_lock);
  294. auto* reg = (u32 volatile*)m_registers_region->vaddr().offset(to_underlying(index)).as_ptr();
  295. u32 value = *reg;
  296. dbgln_if(INTEL_GRAPHICS_DEBUG, "Intel Graphics Display Connector: Read from {} value of {:x}", convert_register_index_to_string(index), value);
  297. return value;
  298. }
  299. bool IntelNativeDisplayConnector::pipe_a_enabled() const
  300. {
  301. VERIFY(m_control_lock.is_locked());
  302. return read_from_register(IntelGraphics::RegisterIndex::PipeAConf) & (1 << 30);
  303. }
  304. bool IntelNativeDisplayConnector::pipe_b_enabled() const
  305. {
  306. VERIFY(m_control_lock.is_locked());
  307. return read_from_register(IntelGraphics::RegisterIndex::PipeBConf) & (1 << 30);
  308. }
  309. bool IntelNativeDisplayConnector::gmbus_wait_for(IntelGraphics::GMBusStatus desired_status, Optional<size_t> milliseconds_timeout)
  310. {
  311. VERIFY(m_control_lock.is_locked());
  312. size_t milliseconds_passed = 0;
  313. while (1) {
  314. if (milliseconds_timeout.has_value() && milliseconds_timeout.value() < milliseconds_passed)
  315. return false;
  316. full_memory_barrier();
  317. u32 status = read_from_register(IntelGraphics::RegisterIndex::GMBusStatus);
  318. full_memory_barrier();
  319. VERIFY(!(status & (1 << 10))); // error happened
  320. switch (desired_status) {
  321. case IntelGraphics::GMBusStatus::HardwareReady:
  322. if (status & (1 << 11))
  323. return true;
  324. break;
  325. case IntelGraphics::GMBusStatus::TransactionCompletion:
  326. if (status & (1 << 14))
  327. return true;
  328. break;
  329. default:
  330. VERIFY_NOT_REACHED();
  331. }
  332. microseconds_delay(1000);
  333. milliseconds_passed++;
  334. }
  335. }
  336. void IntelNativeDisplayConnector::gmbus_write(unsigned address, u32 byte)
  337. {
  338. VERIFY(m_control_lock.is_locked());
  339. VERIFY(address < 256);
  340. full_memory_barrier();
  341. write_to_register(IntelGraphics::RegisterIndex::GMBusData, byte);
  342. full_memory_barrier();
  343. write_to_register(IntelGraphics::RegisterIndex::GMBusCommand, ((address << 1) | (1 << 16) | (IntelGraphics::GMBusCycle::Wait << 25) | (1 << 30)));
  344. full_memory_barrier();
  345. gmbus_wait_for(IntelGraphics::GMBusStatus::TransactionCompletion, {});
  346. }
  347. void IntelNativeDisplayConnector::gmbus_read(unsigned address, u8* buf, size_t length)
  348. {
  349. VERIFY(address < 256);
  350. VERIFY(m_control_lock.is_locked());
  351. size_t nread = 0;
  352. auto read_set = [&] {
  353. full_memory_barrier();
  354. u32 data = read_from_register(IntelGraphics::RegisterIndex::GMBusData);
  355. full_memory_barrier();
  356. for (size_t index = 0; index < 4; index++) {
  357. if (nread == length)
  358. break;
  359. buf[nread] = (data >> (8 * index)) & 0xFF;
  360. nread++;
  361. }
  362. };
  363. full_memory_barrier();
  364. write_to_register(IntelGraphics::RegisterIndex::GMBusCommand, (1 | (address << 1) | (length << 16) | (IntelGraphics::GMBusCycle::Wait << 25) | (1 << 30)));
  365. full_memory_barrier();
  366. while (nread < length) {
  367. gmbus_wait_for(IntelGraphics::GMBusStatus::HardwareReady, {});
  368. read_set();
  369. }
  370. gmbus_wait_for(IntelGraphics::GMBusStatus::TransactionCompletion, {});
  371. }
  372. void IntelNativeDisplayConnector::gmbus_read_edid()
  373. {
  374. Array<u8, 128> crt_edid_bytes {};
  375. {
  376. SpinlockLocker control_lock(m_control_lock);
  377. gmbus_write(DDC2_I2C_ADDRESS, 0);
  378. gmbus_read(DDC2_I2C_ADDRESS, crt_edid_bytes.data(), crt_edid_bytes.size());
  379. }
  380. set_edid_bytes(crt_edid_bytes);
  381. }
  382. bool IntelNativeDisplayConnector::is_resolution_valid(size_t, size_t)
  383. {
  384. VERIFY(m_control_lock.is_locked());
  385. VERIFY(m_modeset_lock.is_locked());
  386. // FIXME: Check that we are able to modeset to the requested resolution!
  387. return true;
  388. }
  389. void IntelNativeDisplayConnector::disable_output()
  390. {
  391. VERIFY(m_control_lock.is_locked());
  392. disable_dac_output();
  393. disable_all_planes();
  394. disable_pipe_a();
  395. disable_pipe_b();
  396. disable_dpll();
  397. disable_vga_emulation();
  398. }
  399. void IntelNativeDisplayConnector::enable_output(PhysicalAddress fb_address, size_t width)
  400. {
  401. VERIFY(m_control_lock.is_locked());
  402. VERIFY(!pipe_a_enabled());
  403. enable_pipe_a();
  404. enable_primary_plane(fb_address, width);
  405. enable_dac_output();
  406. }
  407. static size_t compute_dac_multiplier(size_t pixel_clock_in_khz)
  408. {
  409. dbgln_if(INTEL_GRAPHICS_DEBUG, "Intel native graphics: Pixel clock is {} KHz", pixel_clock_in_khz);
  410. VERIFY(pixel_clock_in_khz >= 25000);
  411. if (pixel_clock_in_khz >= 100000) {
  412. return 1;
  413. } else if (pixel_clock_in_khz >= 50000) {
  414. return 2;
  415. } else {
  416. return 4;
  417. }
  418. }
  419. bool IntelNativeDisplayConnector::set_safe_crt_resolution()
  420. {
  421. VERIFY(m_control_lock.is_locked());
  422. SpinlockLocker modeset_lock(m_modeset_lock);
  423. // Note: Just in case we still allow access to VGA IO ports, disable it now.
  424. GraphicsManagement::the().disable_vga_emulation_access_permanently();
  425. // FIXME: Get the requested resolution from the EDID!!
  426. auto modesetting = calculate_modesetting_from_edid(m_edid_parser.value(), 0);
  427. disable_output();
  428. auto dac_multiplier = compute_dac_multiplier(modesetting.pixel_clock_in_khz);
  429. auto pll_settings = create_pll_settings((1000 * modesetting.pixel_clock_in_khz * dac_multiplier), 96'000'000, IntelGraphics::G35Limits);
  430. if (!pll_settings.has_value())
  431. VERIFY_NOT_REACHED();
  432. auto settings = pll_settings.value();
  433. dbgln_if(INTEL_GRAPHICS_DEBUG, "PLL settings for {} {} {} {} {}", settings.n, settings.m1, settings.m2, settings.p1, settings.p2);
  434. enable_dpll_without_vga(pll_settings.value(), dac_multiplier);
  435. set_display_timings(modesetting);
  436. enable_output(m_framebuffer_address.value(), modesetting.horizontal.blanking_start());
  437. DisplayConnector::ModeSetting mode_set {
  438. .horizontal_stride = modesetting.horizontal.blanking_start() * sizeof(u32),
  439. .pixel_clock_in_khz = 0,
  440. .horizontal_active = modesetting.horizontal.blanking_start(),
  441. .horizontal_front_porch_pixels = 0,
  442. .horizontal_sync_time_pixels = 0,
  443. .horizontal_blank_pixels = 0,
  444. .vertical_active = modesetting.vertical.blanking_start(),
  445. .vertical_front_porch_lines = 0,
  446. .vertical_sync_time_lines = 0,
  447. .vertical_blank_lines = 0,
  448. .horizontal_offset = 0,
  449. .vertical_offset = 0,
  450. };
  451. m_current_mode_setting = mode_set;
  452. if (m_framebuffer_console)
  453. m_framebuffer_console->set_resolution(m_current_mode_setting.horizontal_active, m_current_mode_setting.vertical_active, m_current_mode_setting.horizontal_stride);
  454. return true;
  455. }
  456. void IntelNativeDisplayConnector::set_display_timings(Graphics::Modesetting const& modesetting)
  457. {
  458. VERIFY(m_control_lock.is_locked());
  459. VERIFY(m_modeset_lock.is_locked());
  460. VERIFY(!(read_from_register(IntelGraphics::RegisterIndex::PipeAConf) & (1 << 31)));
  461. VERIFY(!(read_from_register(IntelGraphics::RegisterIndex::PipeAConf) & (1 << 30)));
  462. dbgln_if(INTEL_GRAPHICS_DEBUG, "htotal - {}, {}", (modesetting.horizontal.active - 1), (modesetting.horizontal.total - 1));
  463. write_to_register(IntelGraphics::RegisterIndex::HTotalA, (modesetting.horizontal.active - 1) | (modesetting.horizontal.total - 1) << 16);
  464. dbgln_if(INTEL_GRAPHICS_DEBUG, "hblank - {}, {}", (modesetting.horizontal.blanking_start() - 1), (modesetting.horizontal.blanking_end() - 1));
  465. write_to_register(IntelGraphics::RegisterIndex::HBlankA, (modesetting.horizontal.blanking_start() - 1) | (modesetting.horizontal.blanking_end() - 1) << 16);
  466. dbgln_if(INTEL_GRAPHICS_DEBUG, "hsync - {}, {}", (modesetting.horizontal.sync_start - 1), (modesetting.horizontal.sync_end - 1));
  467. write_to_register(IntelGraphics::RegisterIndex::HSyncA, (modesetting.horizontal.sync_start - 1) | (modesetting.horizontal.sync_end - 1) << 16);
  468. dbgln_if(INTEL_GRAPHICS_DEBUG, "vtotal - {}, {}", (modesetting.vertical.active - 1), (modesetting.vertical.total - 1));
  469. write_to_register(IntelGraphics::RegisterIndex::VTotalA, (modesetting.vertical.active - 1) | (modesetting.vertical.total - 1) << 16);
  470. dbgln_if(INTEL_GRAPHICS_DEBUG, "vblank - {}, {}", (modesetting.vertical.blanking_start() - 1), (modesetting.vertical.blanking_end() - 1));
  471. write_to_register(IntelGraphics::RegisterIndex::VBlankA, (modesetting.vertical.blanking_start() - 1) | (modesetting.vertical.blanking_end() - 1) << 16);
  472. dbgln_if(INTEL_GRAPHICS_DEBUG, "vsync - {}, {}", (modesetting.vertical.sync_start - 1), (modesetting.vertical.sync_end - 1));
  473. write_to_register(IntelGraphics::RegisterIndex::VSyncA, (modesetting.vertical.sync_start - 1) | (modesetting.vertical.sync_end - 1) << 16);
  474. dbgln_if(INTEL_GRAPHICS_DEBUG, "sourceSize - {}, {}", (modesetting.vertical.active - 1), (modesetting.horizontal.active - 1));
  475. write_to_register(IntelGraphics::RegisterIndex::PipeASource, (modesetting.vertical.active - 1) | (modesetting.horizontal.active - 1) << 16);
  476. microseconds_delay(200);
  477. }
  478. bool IntelNativeDisplayConnector::wait_for_enabled_pipe_a(size_t milliseconds_timeout) const
  479. {
  480. size_t current_time = 0;
  481. while (current_time < milliseconds_timeout) {
  482. if (pipe_a_enabled())
  483. return true;
  484. microseconds_delay(1000);
  485. current_time++;
  486. }
  487. return false;
  488. }
  489. bool IntelNativeDisplayConnector::wait_for_disabled_pipe_a(size_t milliseconds_timeout) const
  490. {
  491. size_t current_time = 0;
  492. while (current_time < milliseconds_timeout) {
  493. if (!pipe_a_enabled())
  494. return true;
  495. microseconds_delay(1000);
  496. current_time++;
  497. }
  498. return false;
  499. }
  500. bool IntelNativeDisplayConnector::wait_for_disabled_pipe_b(size_t milliseconds_timeout) const
  501. {
  502. size_t current_time = 0;
  503. while (current_time < milliseconds_timeout) {
  504. if (!pipe_b_enabled())
  505. return true;
  506. microseconds_delay(1000);
  507. current_time++;
  508. }
  509. return false;
  510. }
  511. void IntelNativeDisplayConnector::disable_dpll()
  512. {
  513. VERIFY(m_control_lock.is_locked());
  514. VERIFY(m_modeset_lock.is_locked());
  515. write_to_register(IntelGraphics::RegisterIndex::DPLLControlA, 0);
  516. write_to_register(IntelGraphics::RegisterIndex::DPLLControlB, 0);
  517. }
  518. void IntelNativeDisplayConnector::disable_pipe_a()
  519. {
  520. VERIFY(m_control_lock.is_locked());
  521. VERIFY(m_modeset_lock.is_locked());
  522. write_to_register(IntelGraphics::RegisterIndex::PipeAConf, 0);
  523. dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe A");
  524. wait_for_disabled_pipe_a(100);
  525. dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe A - done.");
  526. }
  527. void IntelNativeDisplayConnector::disable_pipe_b()
  528. {
  529. VERIFY(m_control_lock.is_locked());
  530. VERIFY(m_modeset_lock.is_locked());
  531. write_to_register(IntelGraphics::RegisterIndex::PipeAConf, 0);
  532. dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe B");
  533. wait_for_disabled_pipe_b(100);
  534. dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe B - done.");
  535. }
  536. void IntelNativeDisplayConnector::set_gmbus_default_rate()
  537. {
  538. // FIXME: Verify GMBUS Rate Select is set only when GMBUS is idle
  539. VERIFY(m_control_lock.is_locked());
  540. // Set the rate to 100KHz
  541. write_to_register(IntelGraphics::RegisterIndex::GMBusClock, read_from_register(IntelGraphics::RegisterIndex::GMBusClock) & ~(0b111 << 8));
  542. }
  543. void IntelNativeDisplayConnector::enable_pipe_a()
  544. {
  545. VERIFY(m_control_lock.is_locked());
  546. VERIFY(m_modeset_lock.is_locked());
  547. VERIFY(!(read_from_register(IntelGraphics::RegisterIndex::PipeAConf) & (1 << 31)));
  548. VERIFY(!(read_from_register(IntelGraphics::RegisterIndex::PipeAConf) & (1 << 30)));
  549. write_to_register(IntelGraphics::RegisterIndex::PipeAConf, (1 << 31) | (1 << 24));
  550. dbgln_if(INTEL_GRAPHICS_DEBUG, "enabling Pipe A");
  551. // FIXME: Seems like my video card is buggy and doesn't set the enabled bit (bit 30)!!
  552. wait_for_enabled_pipe_a(100);
  553. dbgln_if(INTEL_GRAPHICS_DEBUG, "enabling Pipe A - done.");
  554. }
  555. void IntelNativeDisplayConnector::enable_primary_plane(PhysicalAddress fb_address, size_t width)
  556. {
  557. VERIFY(m_control_lock.is_locked());
  558. VERIFY(m_modeset_lock.is_locked());
  559. VERIFY(((width * 4) % 64 == 0));
  560. write_to_register(IntelGraphics::RegisterIndex::DisplayPlaneAStride, width * 4);
  561. write_to_register(IntelGraphics::RegisterIndex::DisplayPlaneALinearOffset, 0);
  562. write_to_register(IntelGraphics::RegisterIndex::DisplayPlaneASurface, fb_address.get());
  563. // FIXME: Serenity uses BGR 32 bit pixel format, but maybe we should try to determine it somehow!
  564. write_to_register(IntelGraphics::RegisterIndex::DisplayPlaneAControl, (0b0110 << 26) | (1 << 31));
  565. }
  566. void IntelNativeDisplayConnector::set_dpll_registers(IntelGraphics::PLLSettings const& settings)
  567. {
  568. VERIFY(m_control_lock.is_locked());
  569. VERIFY(m_modeset_lock.is_locked());
  570. write_to_register(IntelGraphics::RegisterIndex::DPLLDivisorA0, (settings.m2 - 2) | ((settings.m1 - 2) << 8) | ((settings.n - 2) << 16));
  571. write_to_register(IntelGraphics::RegisterIndex::DPLLDivisorA1, (settings.m2 - 2) | ((settings.m1 - 2) << 8) | ((settings.n - 2) << 16));
  572. write_to_register(IntelGraphics::RegisterIndex::DPLLControlA, 0);
  573. }
  574. void IntelNativeDisplayConnector::enable_dpll_without_vga(IntelGraphics::PLLSettings const& settings, size_t dac_multiplier)
  575. {
  576. VERIFY(m_control_lock.is_locked());
  577. VERIFY(m_modeset_lock.is_locked());
  578. set_dpll_registers(settings);
  579. microseconds_delay(200);
  580. write_to_register(IntelGraphics::RegisterIndex::DPLLControlA, (6 << 9) | (settings.p1) << 16 | (1 << 26) | (1 << 28) | (1 << 31));
  581. write_to_register(IntelGraphics::RegisterIndex::DPLLMultiplierA, (dac_multiplier - 1) | ((dac_multiplier - 1) << 8));
  582. // The specification says we should wait (at least) about 150 microseconds
  583. // after enabling the DPLL to allow the clock to stabilize
  584. microseconds_delay(200);
  585. VERIFY(read_from_register(IntelGraphics::RegisterIndex::DPLLControlA) & (1 << 31));
  586. }
  587. void IntelNativeDisplayConnector::set_gmbus_pin_pair(IntelGraphics::GMBusPinPair pin_pair)
  588. {
  589. // FIXME: Verify GMBUS is idle
  590. VERIFY(m_control_lock.is_locked());
  591. write_to_register(IntelGraphics::RegisterIndex::GMBusClock, (read_from_register(IntelGraphics::RegisterIndex::GMBusClock) & (~0b111)) | (pin_pair & 0b111));
  592. }
  593. void IntelNativeDisplayConnector::disable_dac_output()
  594. {
  595. VERIFY(m_control_lock.is_locked());
  596. VERIFY(m_modeset_lock.is_locked());
  597. write_to_register(IntelGraphics::RegisterIndex::AnalogDisplayPort, 0b11 << 10);
  598. }
  599. void IntelNativeDisplayConnector::enable_dac_output()
  600. {
  601. VERIFY(m_control_lock.is_locked());
  602. VERIFY(m_modeset_lock.is_locked());
  603. write_to_register(IntelGraphics::RegisterIndex::AnalogDisplayPort, (1 << 31));
  604. }
  605. void IntelNativeDisplayConnector::disable_vga_emulation()
  606. {
  607. VERIFY(m_control_lock.is_locked());
  608. VERIFY(m_modeset_lock.is_locked());
  609. write_to_register(IntelGraphics::RegisterIndex::VGADisplayPlaneControl, (1 << 31));
  610. read_from_register(IntelGraphics::RegisterIndex::VGADisplayPlaneControl);
  611. }
  612. void IntelNativeDisplayConnector::disable_all_planes()
  613. {
  614. VERIFY(m_control_lock.is_locked());
  615. VERIFY(m_modeset_lock.is_locked());
  616. write_to_register(IntelGraphics::RegisterIndex::DisplayPlaneAControl, 0);
  617. write_to_register(IntelGraphics::RegisterIndex::DisplayPlaneBControl, 0);
  618. }
  619. }