From 8042ae43c339f59980ae953bbae2ea2d5a743241 Mon Sep 17 00:00:00 2001 From: Liav A Date: Fri, 1 Apr 2022 12:52:49 +0300 Subject: [PATCH] Kernel/IntelGraphics: Move pipe management to the Transcoder class It became apparent to me that future generations of the Intel graphics chipset utilize the same register set as part of the Transcoder register set. Therefore, it should be included now in the Transcoder class. --- Kernel/Graphics/Intel/Definitions.h | 5 - .../Graphics/Intel/DisplayConnectorGroup.cpp | 102 ++---------------- Kernel/Graphics/Intel/DisplayConnectorGroup.h | 13 --- .../Transcoder/AnalogDisplayTranscoder.cpp | 9 +- .../Transcoder/AnalogDisplayTranscoder.h | 4 +- .../Intel/Transcoder/DisplayTranscoder.cpp | 55 +++++++++- .../Intel/Transcoder/DisplayTranscoder.h | 29 ++++- 7 files changed, 95 insertions(+), 122 deletions(-) diff --git a/Kernel/Graphics/Intel/Definitions.h b/Kernel/Graphics/Intel/Definitions.h index 46306ba287..699a8d2231 100644 --- a/Kernel/Graphics/Intel/Definitions.h +++ b/Kernel/Graphics/Intel/Definitions.h @@ -10,11 +10,6 @@ namespace Kernel::IntelGraphics { -enum class GlobalGenerationRegister { - PipeAConf = 0x70008, - PipeBConf = 0x71008, -}; - struct PLLSettings; struct PLLParameterLimit { diff --git a/Kernel/Graphics/Intel/DisplayConnectorGroup.cpp b/Kernel/Graphics/Intel/DisplayConnectorGroup.cpp index 86af3c91b0..3106dc68fb 100644 --- a/Kernel/Graphics/Intel/DisplayConnectorGroup.cpp +++ b/Kernel/Graphics/Intel/DisplayConnectorGroup.cpp @@ -147,12 +147,14 @@ ErrorOr IntelDisplayConnectorGroup::initialize_gen4_connectors() // NOTE: Just assume we will need one Gen4 "transcoder" // NOTE: Main block of registers starting at HorizontalTotalA register (0x60000) auto transcoder_registers_paddr = m_mmio_first_region.pci_bar_paddr.offset(0x60000); + // NOTE: Main block of Pipe registers starting at PipeA_DSL register (0x70000) + auto pipe_registers_paddr = m_mmio_first_region.pci_bar_paddr.offset(0x70000); // NOTE: DPLL registers starting at DPLLDivisorA0 register (0x6040) auto dpll_registers_paddr = m_mmio_first_region.pci_bar_paddr.offset(0x6040); // NOTE: DPLL A control registers starting at 0x6014 (DPLL A Control register), // DPLL A Multiplier is at 0x601C, between them (at 0x6018) there is the DPLL B Control register. auto dpll_control_registers_paddr = m_mmio_first_region.pci_bar_paddr.offset(0x6014); - m_transcoders[0] = TRY(IntelAnalogDisplayTranscoder::create_with_physical_addresses(transcoder_registers_paddr, dpll_registers_paddr, dpll_control_registers_paddr)); + m_transcoders[0] = TRY(IntelAnalogDisplayTranscoder::create_with_physical_addresses(transcoder_registers_paddr, pipe_registers_paddr, dpll_registers_paddr, dpll_control_registers_paddr)); m_planes[0] = TRY(IntelG33DisplayPlane::create_with_physical_address(m_mmio_first_region.pci_bar_paddr.offset(0x70180))); Array crt_edid_bytes {}; { @@ -299,29 +301,6 @@ u32 IntelDisplayConnectorGroup::read_from_analog_output_register(AnalogOutputReg return value; } -void IntelDisplayConnectorGroup::write_to_global_generation_register(IntelGraphics::GlobalGenerationRegister index, u32 value) -{ - write_to_general_register(to_underlying(index), value); -} - -u32 IntelDisplayConnectorGroup::read_from_global_generation_register(IntelGraphics::GlobalGenerationRegister index) const -{ - u32 value = read_from_general_register(to_underlying(index)); - return value; -} - -bool IntelDisplayConnectorGroup::pipe_a_enabled() const -{ - VERIFY(m_control_lock.is_locked()); - return read_from_global_generation_register(IntelGraphics::GlobalGenerationRegister::PipeAConf) & (1 << 30); -} - -bool IntelDisplayConnectorGroup::pipe_b_enabled() const -{ - VERIFY(m_control_lock.is_locked()); - return read_from_global_generation_register(IntelGraphics::GlobalGenerationRegister::PipeBConf) & (1 << 30); -} - static size_t compute_dac_multiplier(size_t pixel_clock_in_khz) { dbgln_if(INTEL_GRAPHICS_DEBUG, "Intel native graphics: Pixel clock is {} KHz", pixel_clock_in_khz); @@ -351,8 +330,7 @@ bool IntelDisplayConnectorGroup::set_crt_resolution(DisplayConnector::ModeSettin disable_dac_output(); MUST(m_planes[0]->disable({})); - disable_pipe_a(); - disable_pipe_b(); + MUST(m_transcoders[0]->disable_pipe({})); MUST(m_transcoders[0]->disable_dpll({})); disable_vga_emulation(); @@ -362,8 +340,8 @@ bool IntelDisplayConnectorGroup::set_crt_resolution(DisplayConnector::ModeSettin MUST(m_transcoders[0]->enable_dpll_without_vga({})); MUST(m_transcoders[0]->set_mode_setting_timings({}, mode_setting)); - VERIFY(!pipe_a_enabled()); - enable_pipe_a(); + VERIFY(!m_transcoders[0]->pipe_enabled({})); + MUST(m_transcoders[0]->enable_pipe({})); MUST(m_planes[0]->set_plane_settings({}, m_mmio_second_region.pci_bar_paddr, IntelDisplayPlane::PipeSelect::PipeA, mode_setting.horizontal_active)); MUST(m_planes[0]->enable({})); enable_dac_output(); @@ -371,74 +349,6 @@ bool IntelDisplayConnectorGroup::set_crt_resolution(DisplayConnector::ModeSettin return true; } -bool IntelDisplayConnectorGroup::wait_for_enabled_pipe_a(size_t milliseconds_timeout) const -{ - size_t current_time = 0; - while (current_time < milliseconds_timeout) { - if (pipe_a_enabled()) - return true; - microseconds_delay(1000); - current_time++; - } - return false; -} -bool IntelDisplayConnectorGroup::wait_for_disabled_pipe_a(size_t milliseconds_timeout) const -{ - size_t current_time = 0; - while (current_time < milliseconds_timeout) { - if (!pipe_a_enabled()) - return true; - microseconds_delay(1000); - current_time++; - } - return false; -} - -bool IntelDisplayConnectorGroup::wait_for_disabled_pipe_b(size_t milliseconds_timeout) const -{ - size_t current_time = 0; - while (current_time < milliseconds_timeout) { - if (!pipe_b_enabled()) - return true; - microseconds_delay(1000); - current_time++; - } - return false; -} - -void IntelDisplayConnectorGroup::disable_pipe_a() -{ - VERIFY(m_control_lock.is_locked()); - VERIFY(m_modeset_lock.is_locked()); - write_to_global_generation_register(IntelGraphics::GlobalGenerationRegister::PipeAConf, 0); - dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe A"); - wait_for_disabled_pipe_a(100); - dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe A - done."); -} - -void IntelDisplayConnectorGroup::disable_pipe_b() -{ - VERIFY(m_control_lock.is_locked()); - VERIFY(m_modeset_lock.is_locked()); - write_to_global_generation_register(IntelGraphics::GlobalGenerationRegister::PipeAConf, 0); - dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe B"); - wait_for_disabled_pipe_b(100); - dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe B - done."); -} - -void IntelDisplayConnectorGroup::enable_pipe_a() -{ - VERIFY(m_control_lock.is_locked()); - VERIFY(m_modeset_lock.is_locked()); - VERIFY(!(read_from_global_generation_register(IntelGraphics::GlobalGenerationRegister::PipeAConf) & (1 << 31))); - VERIFY(!(read_from_global_generation_register(IntelGraphics::GlobalGenerationRegister::PipeAConf) & (1 << 30))); - write_to_global_generation_register(IntelGraphics::GlobalGenerationRegister::PipeAConf, (1 << 31) | (1 << 24)); - dbgln_if(INTEL_GRAPHICS_DEBUG, "enabling Pipe A"); - // FIXME: Seems like my video card is buggy and doesn't set the enabled bit (bit 30)!! - wait_for_enabled_pipe_a(100); - dbgln_if(INTEL_GRAPHICS_DEBUG, "enabling Pipe A - done."); -} - void IntelDisplayConnectorGroup::disable_dac_output() { VERIFY(m_control_lock.is_locked()); diff --git a/Kernel/Graphics/Intel/DisplayConnectorGroup.h b/Kernel/Graphics/Intel/DisplayConnectorGroup.h index f5b93a6a9d..db14ab4414 100644 --- a/Kernel/Graphics/Intel/DisplayConnectorGroup.h +++ b/Kernel/Graphics/Intel/DisplayConnectorGroup.h @@ -60,8 +60,6 @@ private: StringView convert_analog_output_register_to_string(AnalogOutputRegisterOffset index) const; void write_to_analog_output_register(AnalogOutputRegisterOffset, u32 value); u32 read_from_analog_output_register(AnalogOutputRegisterOffset) const; - u32 read_from_global_generation_register(IntelGraphics::GlobalGenerationRegister index) const; - void write_to_global_generation_register(IntelGraphics::GlobalGenerationRegister index, u32 value); void write_to_general_register(RegisterOffset offset, u32 value); u32 read_from_general_register(RegisterOffset offset) const; @@ -71,8 +69,6 @@ private: // General Modesetting methods ErrorOr set_gen4_mode_setting(IntelNativeDisplayConnector&, DisplayConnector::ModeSetting const&); - bool pipe_a_enabled() const; - bool pipe_b_enabled() const; bool set_crt_resolution(DisplayConnector::ModeSetting const&); @@ -82,15 +78,6 @@ private: void disable_dac_output(); void enable_dac_output(); - void disable_pipe_a(); - void disable_pipe_b(); - - void enable_pipe_a(); - - bool wait_for_enabled_pipe_a(size_t milliseconds_timeout) const; - bool wait_for_disabled_pipe_a(size_t milliseconds_timeout) const; - bool wait_for_disabled_pipe_b(size_t milliseconds_timeout) const; - Optional create_pll_settings(u64 target_frequency, u64 reference_clock, IntelGraphics::PLLMaxSettings const&); Spinlock m_control_lock; diff --git a/Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.cpp b/Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.cpp index af86115a05..3d9600995d 100644 --- a/Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.cpp +++ b/Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.cpp @@ -11,17 +11,18 @@ namespace Kernel { ErrorOr> IntelAnalogDisplayTranscoder::create_with_physical_addresses(PhysicalAddress transcoder_registers_start_address, - PhysicalAddress dpll_registers_start_address, PhysicalAddress dpll_multiplier_register_start_address) + PhysicalAddress pipe_registers_start_address, PhysicalAddress dpll_registers_start_address, PhysicalAddress dpll_multiplier_register_start_address) { auto transcoder_registers_mapping = TRY(Memory::map_typed(transcoder_registers_start_address, sizeof(IntelDisplayTranscoder::TranscoderRegisters), Memory::Region::Access::ReadWrite)); + auto pipe_registers_mapping = TRY(Memory::map_typed(pipe_registers_start_address, sizeof(IntelDisplayTranscoder::PipeRegisters), Memory::Region::Access::ReadWrite)); auto dpll_registers_mapping = TRY(Memory::map_typed(dpll_registers_start_address, sizeof(DPLLRegisters), Memory::Region::Access::ReadWrite)); auto dpll_control_mapping = TRY(Memory::map_typed(dpll_multiplier_register_start_address, sizeof(DPLLControlRegisters), Memory::Region::Access::ReadWrite)); - return adopt_nonnull_own_or_enomem(new (nothrow) IntelAnalogDisplayTranscoder(move(transcoder_registers_mapping), move(dpll_registers_mapping), move(dpll_control_mapping))); + return adopt_nonnull_own_or_enomem(new (nothrow) IntelAnalogDisplayTranscoder(move(transcoder_registers_mapping), move(pipe_registers_mapping), move(dpll_registers_mapping), move(dpll_control_mapping))); } IntelAnalogDisplayTranscoder::IntelAnalogDisplayTranscoder(Memory::TypedMapping transcoder_registers_mapping, - Memory::TypedMapping dpll_registers_mapping, Memory::TypedMapping dpll_control_registers) - : IntelDisplayTranscoder(move(transcoder_registers_mapping)) + Memory::TypedMapping pipe_registers_mapping, Memory::TypedMapping dpll_registers_mapping, Memory::TypedMapping dpll_control_registers) + : IntelDisplayTranscoder(move(transcoder_registers_mapping), move(pipe_registers_mapping)) , m_dpll_registers(move(dpll_registers_mapping)) , m_dpll_control_registers(move(dpll_control_registers)) { diff --git a/Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.h b/Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.h index ac0ff9e725..32c1cf0cbc 100644 --- a/Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.h +++ b/Kernel/Graphics/Intel/Transcoder/AnalogDisplayTranscoder.h @@ -17,7 +17,7 @@ class IntelDisplayConnectorGroup; class IntelAnalogDisplayTranscoder final : public IntelDisplayTranscoder { public: static ErrorOr> create_with_physical_addresses(PhysicalAddress transcoder_registers_start_address, - PhysicalAddress dpll_registers_start_address, PhysicalAddress dpll_control_registers_start_address); + PhysicalAddress pipe_registers_start_address, PhysicalAddress dpll_registers_start_address, PhysicalAddress dpll_control_registers_start_address); virtual ErrorOr set_dpll_settings(Badge, IntelGraphics::PLLSettings const& settings, size_t dac_multiplier) override; virtual ErrorOr enable_dpll_without_vga(Badge) override; @@ -35,7 +35,7 @@ private: u32 multiplier; }; - IntelAnalogDisplayTranscoder(Memory::TypedMapping, Memory::TypedMapping, Memory::TypedMapping); + IntelAnalogDisplayTranscoder(Memory::TypedMapping, Memory::TypedMapping, Memory::TypedMapping, Memory::TypedMapping); Memory::TypedMapping m_dpll_registers; Memory::TypedMapping m_dpll_control_registers; }; diff --git a/Kernel/Graphics/Intel/Transcoder/DisplayTranscoder.cpp b/Kernel/Graphics/Intel/Transcoder/DisplayTranscoder.cpp index 72fbc5ca9c..4836538615 100644 --- a/Kernel/Graphics/Intel/Transcoder/DisplayTranscoder.cpp +++ b/Kernel/Graphics/Intel/Transcoder/DisplayTranscoder.cpp @@ -4,13 +4,15 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include namespace Kernel { -IntelDisplayTranscoder::IntelDisplayTranscoder(Memory::TypedMapping registers_mapping) +IntelDisplayTranscoder::IntelDisplayTranscoder(Memory::TypedMapping registers_mapping, Memory::TypedMapping pipe_registers_mapping) : m_transcoder_registers(move(registers_mapping)) + , m_pipe_registers(move(pipe_registers_mapping)) { } @@ -54,4 +56,55 @@ ErrorOr IntelDisplayTranscoder::set_mode_setting_timings(Badge IntelDisplayTranscoder::disable_pipe(Badge) +{ + SpinlockLocker locker(m_access_lock); + m_pipe_registers->pipe_configuration = 0; + m_shadow_registers.pipe_conf = 0; + dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe"); + size_t milliseconds_elapsed = 0; + while (milliseconds_elapsed < 100) { + u32 value = m_pipe_registers->pipe_configuration; + if (!(value & (1 << 30))) + return {}; + microseconds_delay(1000); + milliseconds_elapsed++; + } + return Error::from_errno(EBUSY); +} + +ErrorOr IntelDisplayTranscoder::enable_pipe(Badge) +{ + SpinlockLocker locker(m_access_lock); + u32 value = m_pipe_registers->pipe_configuration; + // Note: Just verify these are not already enabled... + if ((value & (1 << 30)) && (value & (1 << 31))) + return {}; + + // Note: Set the pipe configuration register with these bits: + // 1. Bit 31 - to enable the Pipe + // 2. Bit 24 - to enable Gamma Unit Mode to 10 bit Gamma mode. + // 3. Bits 21-23 are set to zero to indicate Progressive mode (non Interlaced mode) + // 4. Bits 18 and 19 are set to zero to indicate Normal operations of assigned + // Cursor and Display planes. + m_pipe_registers->pipe_configuration = (1 << 31) | (1 << 24); + m_shadow_registers.pipe_conf = (1 << 31) | (1 << 24); + dbgln_if(INTEL_GRAPHICS_DEBUG, "Enabling Pipe"); + size_t milliseconds_elapsed = 0; + while (milliseconds_elapsed < 100) { + u32 value = m_pipe_registers->pipe_configuration; + if ((value & (1 << 30))) + return {}; + microseconds_delay(1000); + milliseconds_elapsed++; + } + // FIXME: Seems like my video card is buggy and doesn't set the enabled bit (bit 30)!! + return {}; +} +bool IntelDisplayTranscoder::pipe_enabled(Badge) const +{ + SpinlockLocker locker(m_access_lock); + u32 value = m_pipe_registers->pipe_configuration; + return (value & (1 << 30)); +} } diff --git a/Kernel/Graphics/Intel/Transcoder/DisplayTranscoder.h b/Kernel/Graphics/Intel/Transcoder/DisplayTranscoder.h index 1a6551cfb7..9ad038ee76 100644 --- a/Kernel/Graphics/Intel/Transcoder/DisplayTranscoder.h +++ b/Kernel/Graphics/Intel/Transcoder/DisplayTranscoder.h @@ -48,6 +48,7 @@ public: u32 n1_link; u32 m2_link; u32 n2_link; + u32 pipe_conf; }; ErrorOr set_mode_setting_timings(Badge, DisplayConnector::ModeSetting const&); @@ -55,6 +56,10 @@ public: virtual ErrorOr enable_dpll_without_vga(Badge) = 0; virtual ErrorOr disable_dpll(Badge) = 0; + ErrorOr disable_pipe(Badge); + ErrorOr enable_pipe(Badge); + bool pipe_enabled(Badge) const; + ShadowRegisters current_registers_state() const; virtual ~IntelDisplayTranscoder() = default; @@ -83,9 +88,31 @@ protected: u32 n2_link; }; - explicit IntelDisplayTranscoder(Memory::TypedMapping); + struct [[gnu::packed]] PipeRegisters { + u32 pipe_display_scan_line; + u32 pipe_display_scan_line_count_range_compare; + u32 pipe_configuration; + u32 reserved; + u32 pipe_gamma_correction_max_red; + u32 pipe_gamma_correction_max_green; + u32 pipe_gamma_correction_max_blue; + u32 reserved2[2]; + u32 pipe_display_status; + u32 reserved3[2]; + u32 display_arbitration_control; + u32 display_fifo_watermark_control1; + u32 display_fifo_watermark_control2; + u32 display_fifo_watermark_control3; + u32 pipe_frame_count_high; + // Note: The specification calls this "Pipe Frame Count Low and Pixel Count" + u32 pipe_frame_count_low; + }; + + IntelDisplayTranscoder(Memory::TypedMapping, Memory::TypedMapping); mutable Spinlock m_access_lock; + ShadowRegisters m_shadow_registers {}; Memory::TypedMapping m_transcoder_registers; + Memory::TypedMapping m_pipe_registers; }; }