Serenity Operating System
1/*
2 * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <Kernel/Arch/Delay.h>
8#include <Kernel/Graphics/Intel/Transcoder/DisplayTranscoder.h>
9#include <Kernel/PhysicalAddress.h>
10
11namespace Kernel {
12
13IntelDisplayTranscoder::IntelDisplayTranscoder(Memory::TypedMapping<TranscoderRegisters volatile> registers_mapping, Memory::TypedMapping<PipeRegisters volatile> pipe_registers_mapping)
14 : m_transcoder_registers(move(registers_mapping))
15 , m_pipe_registers(move(pipe_registers_mapping))
16{
17}
18
19IntelDisplayTranscoder::ShadowRegisters IntelDisplayTranscoder::current_registers_state() const
20{
21 SpinlockLocker locker(m_access_lock);
22 return m_shadow_registers;
23}
24
25ErrorOr<void> IntelDisplayTranscoder::set_mode_setting_timings(Badge<IntelDisplayConnectorGroup>, DisplayConnector::ModeSetting const& mode_setting)
26{
27 SpinlockLocker locker(m_access_lock);
28
29 dbgln_if(INTEL_GRAPHICS_DEBUG, "htotal - {}, {}", (mode_setting.horizontal_active - 1), (mode_setting.horizontal_total() - 1));
30 m_shadow_registers.horizontal_total = ((mode_setting.horizontal_active - 1) | (mode_setting.horizontal_total() - 1) << 16);
31 m_transcoder_registers->horizontal_total = ((mode_setting.horizontal_active - 1) | (mode_setting.horizontal_total() - 1) << 16);
32
33 dbgln_if(INTEL_GRAPHICS_DEBUG, "hblank - {}, {}", (mode_setting.horizontal_blanking_start() - 1), (mode_setting.horizontal_blanking_start() + mode_setting.horizontal_blank_pixels - 1));
34 m_shadow_registers.horizontal_blank = ((mode_setting.horizontal_blanking_start() - 1) | (mode_setting.horizontal_blanking_start() + mode_setting.horizontal_blank_pixels - 1) << 16);
35 m_transcoder_registers->horizontal_blank = ((mode_setting.horizontal_blanking_start() - 1) | (mode_setting.horizontal_blanking_start() + mode_setting.horizontal_blank_pixels - 1) << 16);
36
37 dbgln_if(INTEL_GRAPHICS_DEBUG, "hsync - {}, {}", (mode_setting.horizontal_sync_start() - 1), (mode_setting.horizontal_sync_end() - 1));
38 m_shadow_registers.horizontal_sync = ((mode_setting.horizontal_sync_start() - 1) | (mode_setting.horizontal_sync_end() - 1) << 16);
39 m_transcoder_registers->horizontal_sync = ((mode_setting.horizontal_sync_start() - 1) | (mode_setting.horizontal_sync_end() - 1) << 16);
40
41 dbgln_if(INTEL_GRAPHICS_DEBUG, "vtotal - {}, {}", (mode_setting.vertical_active - 1), (mode_setting.vertical_blanking_start() + mode_setting.vertical_blank_lines - 1));
42 m_shadow_registers.vertical_total = ((mode_setting.vertical_active - 1) | (mode_setting.vertical_blanking_start() + mode_setting.vertical_blank_lines - 1) << 16);
43 m_transcoder_registers->vertical_total = ((mode_setting.vertical_active - 1) | (mode_setting.vertical_blanking_start() + mode_setting.vertical_blank_lines - 1) << 16);
44
45 dbgln_if(INTEL_GRAPHICS_DEBUG, "vblank - {}, {}", (mode_setting.vertical_blanking_start() - 1), (mode_setting.vertical_blanking_start() + mode_setting.vertical_blank_lines - 1));
46 m_shadow_registers.vertical_blank = ((mode_setting.vertical_blanking_start() - 1) | (mode_setting.vertical_blanking_start() + mode_setting.vertical_blank_lines - 1) << 16);
47 m_transcoder_registers->vertical_blank = ((mode_setting.vertical_blanking_start() - 1) | (mode_setting.vertical_blanking_start() + mode_setting.vertical_blank_lines - 1) << 16);
48
49 dbgln_if(INTEL_GRAPHICS_DEBUG, "vsync - {}, {}", (mode_setting.vertical_sync_start() - 1), (mode_setting.vertical_sync_end() - 1));
50 m_shadow_registers.vertical_sync = ((mode_setting.vertical_sync_start() - 1) | (mode_setting.vertical_sync_end() - 1) << 16);
51 m_transcoder_registers->vertical_sync = ((mode_setting.vertical_sync_start() - 1) | (mode_setting.vertical_sync_end() - 1) << 16);
52
53 dbgln_if(INTEL_GRAPHICS_DEBUG, "sourceSize - {}, {}", (mode_setting.vertical_active - 1), (mode_setting.horizontal_active - 1));
54 m_shadow_registers.pipe_source = ((mode_setting.vertical_active - 1) | (mode_setting.horizontal_active - 1) << 16);
55 m_transcoder_registers->pipe_source = ((mode_setting.vertical_active - 1) | (mode_setting.horizontal_active - 1) << 16);
56 return {};
57}
58
59ErrorOr<void> IntelDisplayTranscoder::disable_pipe(Badge<IntelDisplayConnectorGroup>)
60{
61 SpinlockLocker locker(m_access_lock);
62 m_pipe_registers->pipe_configuration = 0;
63 m_shadow_registers.pipe_conf = 0;
64 dbgln_if(INTEL_GRAPHICS_DEBUG, "Disabling Pipe");
65 size_t milliseconds_elapsed = 0;
66 while (milliseconds_elapsed < 100) {
67 u32 value = m_pipe_registers->pipe_configuration;
68 if (!(value & (1 << 30)))
69 return {};
70 microseconds_delay(1000);
71 milliseconds_elapsed++;
72 }
73 return Error::from_errno(EBUSY);
74}
75
76ErrorOr<void> IntelDisplayTranscoder::enable_pipe(Badge<IntelDisplayConnectorGroup>)
77{
78 SpinlockLocker locker(m_access_lock);
79 u32 value = m_pipe_registers->pipe_configuration;
80 // Note: Just verify these are not already enabled...
81 if ((value & (1 << 30)) && (value & (1 << 31)))
82 return {};
83
84 // Note: Set the pipe configuration register with these bits:
85 // 1. Bit 31 - to enable the Pipe
86 // 2. Bit 24 - to enable Gamma Unit Mode to 10 bit Gamma mode.
87 // 3. Bits 21-23 are set to zero to indicate Progressive mode (non Interlaced mode)
88 // 4. Bits 18 and 19 are set to zero to indicate Normal operations of assigned
89 // Cursor and Display planes.
90 m_pipe_registers->pipe_configuration = (1 << 31) | (1 << 24);
91 m_shadow_registers.pipe_conf = (1 << 31) | (1 << 24);
92 dbgln_if(INTEL_GRAPHICS_DEBUG, "Enabling Pipe");
93 size_t milliseconds_elapsed = 0;
94 while (milliseconds_elapsed < 100) {
95 u32 value = m_pipe_registers->pipe_configuration;
96 if ((value & (1 << 30)))
97 return {};
98 microseconds_delay(1000);
99 milliseconds_elapsed++;
100 }
101 // FIXME: Seems like my video card is buggy and doesn't set the enabled bit (bit 30)!!
102 return {};
103}
104bool IntelDisplayTranscoder::pipe_enabled(Badge<IntelDisplayConnectorGroup>) const
105{
106 SpinlockLocker locker(m_access_lock);
107 u32 value = m_pipe_registers->pipe_configuration;
108 return (value & (1 << 30));
109}
110}