NativeGraphicsAdapter.cpp 27 KB

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