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; }; }