mirror of
https://github.com/RGBCube/serenity
synced 2025-05-19 03:55:07 +00:00

A bit old but a relatively uncomplicated device capable of outputting 1920x1080 video with 32-bit color. Tested with a Voodoo 3 3000 16MB PCI card. Resolution switching from DisplaySettings also works. If the requested mode contains timing information, it is used directly. Otherwise, display timing values are selected from the EDID. First the detailed timings are checked, and then standard and established timings for which there is a matching DMT mode. The driver does not (yet) read the actual EDID, so the generic EDID in DisplayConnector now includes a set of common display modes to make this work. The driver should also be compatible with the Voodoo Banshee, 4 and 5 but I don't have these cards to test this with. The PCI IDs of these cards are included as a commented line in case someone wants to give it a try.
209 lines
5 KiB
C++
209 lines
5 KiB
C++
/*
|
|
* Copyright (c) 2023, Edwin Rijkee <edwin@virtualparadise.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Array.h>
|
|
#include <AK/Types.h>
|
|
|
|
namespace Kernel::VoodooGraphics {
|
|
|
|
enum class VGAPort : u16 {
|
|
AttributeController = 0x3c0,
|
|
MiscOutputWrite = 0x3c2,
|
|
SequencerIndex = 0x3c4,
|
|
SequencerData = 0x3c5,
|
|
MiscOutputRead = 0x3cc,
|
|
GraphicsControllerIndex = 0x3ce,
|
|
GraphicsControllerData = 0x3cf,
|
|
CrtcIndex = 0x3d4,
|
|
CrtcData = 0x3d5,
|
|
InputStatus1 = 0x3da,
|
|
};
|
|
|
|
enum CRTCHorizontalBlankingEndFlags : u8 {
|
|
CompatibilityRead = 1 << 7
|
|
};
|
|
|
|
enum CRTCVerticalSyncEndFlags : u8 {
|
|
EnableVertInt = 1 << 5,
|
|
CRTCRegsWriteProt = 1 << 7
|
|
};
|
|
|
|
enum CRTCModeControlFlags : u8 {
|
|
ByteWordMode = 1 << 6,
|
|
TimingEnable = 1 << 7
|
|
};
|
|
|
|
enum GraphicsControllerMiscellaneousFlags : u8 {
|
|
MemoryMapEGAVGAExtended = 1 << 2,
|
|
};
|
|
|
|
enum AttributeControllerModeFlags : u8 {
|
|
GraphicsMode = 1 << 0,
|
|
PixelWidth = 1 << 6,
|
|
};
|
|
|
|
enum SequencerResetFlags : u8 {
|
|
AsynchronousReset = 1 << 0,
|
|
SynchronousReset = 1 << 1,
|
|
};
|
|
|
|
enum SequencerClockingModeFlags : u8 {
|
|
DotClock8 = 1 << 0,
|
|
};
|
|
|
|
enum MiscellaneousOutputFlags : u8 {
|
|
CRTCAddressColor = 1 << 0,
|
|
ClockSelectPLL = 0b1100,
|
|
VerticalSyncPositive = 1 << 7,
|
|
HorizontalSyncPositive = 1 << 6,
|
|
};
|
|
|
|
enum DacModeFlags : u32 {
|
|
DacMode2x = 1 << 0,
|
|
};
|
|
|
|
enum VgaInit0Flags : u32 {
|
|
FIFODepth8Bit = 1 << 2,
|
|
EnableVgaExtensions = 1 << 6,
|
|
WakeUpSelect3C3 = 1 << 8,
|
|
EnableAltReadback = 1 << 10,
|
|
ExtendedShiftOut = 1 << 12,
|
|
};
|
|
|
|
enum VidProcCfgFlags : u32 {
|
|
VideoProcessorEnable = 1 << 0,
|
|
DesktopSurfaceEnable = 1 << 7,
|
|
DesktopCLUTBypass = 1 << 10,
|
|
DesktopPixelFormat32Bit = 0b11 << 18,
|
|
TwoXMode = 1 << 26,
|
|
};
|
|
|
|
struct PLLSettings {
|
|
static i32 const reference_frequency_in_khz = 14318;
|
|
i32 m = 0;
|
|
i32 n = 0;
|
|
i32 k = 0;
|
|
|
|
int frequency_in_khz() const
|
|
{
|
|
return (reference_frequency_in_khz * (n + 2) / (m + 2)) >> k;
|
|
}
|
|
|
|
u32 register_value() const
|
|
{
|
|
return (n << 8) | (m << 2) | k;
|
|
}
|
|
};
|
|
|
|
// CRT Controller Registers
|
|
struct CRRegisters {
|
|
u8 horizontal_total; // CR0
|
|
u8 horizontal_display_enable_end; // CR1
|
|
u8 horizontal_blanking_start; // CR2
|
|
u8 horizontal_blanking_end; // CR3
|
|
u8 horizontal_sync_start; // CR4
|
|
u8 horizontal_sync_end; // CR5
|
|
u8 vertical_total; // CR6
|
|
u8 overflow; // CR7
|
|
u8 reserved_0; // CR8
|
|
u8 maximum_scan_line; // CR9
|
|
u8 reserved_1[6];
|
|
u8 vertical_sync_start; // CR10
|
|
u8 vertical_sync_end; // CR11
|
|
u8 vertical_display_enable_end; // CR12
|
|
u8 reserved_2[2];
|
|
u8 vertical_blanking_start; // CR15
|
|
u8 vertical_blanking_end; // CR16
|
|
u8 mode_control; // CR17
|
|
u8 reserved_3[2];
|
|
u8 horizontal_extensions; // CR1A
|
|
u8 vertical_extensions; // CR1B
|
|
};
|
|
|
|
// Graphics Controller Registers
|
|
struct GRRegisters {
|
|
u8 reserved_0[6];
|
|
u8 graphics_controller_miscellaneous; // GR6
|
|
u8 reserved_1[2];
|
|
};
|
|
|
|
// Attribute Controller Registers
|
|
struct ARRegisters {
|
|
u8 reserved_0[15];
|
|
u8 attribute_controller_mode; // AR10
|
|
u8 reserved_1[5];
|
|
};
|
|
|
|
// Sequencer Registers
|
|
struct SRRegisters {
|
|
u8 sequencer_reset; // SR0
|
|
u8 sequencer_clocking_mode; // SR1
|
|
u8 reserved[3];
|
|
};
|
|
|
|
struct ModeRegisters {
|
|
u32 vid_screen_size = 0;
|
|
u32 vid_desktop_overlay_stride = 0;
|
|
u8 misc_out_reg = 0;
|
|
u32 vga_init0 = 0;
|
|
u32 vid_proc_cfg = 0;
|
|
u32 dac_mode = 0;
|
|
u32 pll_ctrl0 = 0;
|
|
|
|
union {
|
|
Array<u8, 0x1c> cr_data = { 0 };
|
|
CRRegisters cr;
|
|
};
|
|
|
|
union {
|
|
Array<u8, 0x09> gr_data = { 0 };
|
|
GRRegisters gr;
|
|
};
|
|
|
|
union {
|
|
Array<u8, 0x15> ar_data = { 0 };
|
|
ARRegisters ar;
|
|
};
|
|
|
|
union {
|
|
Array<u8, 0x05> sr_data = { 0 };
|
|
SRRegisters sr;
|
|
};
|
|
};
|
|
|
|
static_assert(sizeof(ModeRegisters::cr_data) == sizeof(ModeRegisters::cr));
|
|
static_assert(sizeof(ModeRegisters::gr_data) == sizeof(ModeRegisters::gr));
|
|
static_assert(sizeof(ModeRegisters::ar_data) == sizeof(ModeRegisters::ar));
|
|
|
|
struct [[gnu::packed]] RegisterMap {
|
|
u32 status;
|
|
u32 reserved_0[9];
|
|
u32 vga_init0;
|
|
u32 reserved_1[5];
|
|
u32 pll_ctrl0;
|
|
u32 reserved_2[2];
|
|
u32 dac_mode;
|
|
u32 reserved_3[3];
|
|
|
|
u32 vid_proc_cfg;
|
|
u32 reserved_4[14];
|
|
u32 vid_screen_size;
|
|
u32 reserved_5[18];
|
|
u32 vid_desktop_start_addr;
|
|
u32 vid_desktop_overlay_stride;
|
|
};
|
|
|
|
static_assert(__builtin_offsetof(RegisterMap, status) == 0);
|
|
static_assert(__builtin_offsetof(RegisterMap, vga_init0) == 0x28);
|
|
static_assert(__builtin_offsetof(RegisterMap, pll_ctrl0) == 0x40);
|
|
static_assert(__builtin_offsetof(RegisterMap, dac_mode) == 0x4c);
|
|
static_assert(__builtin_offsetof(RegisterMap, vid_proc_cfg) == 0x5c);
|
|
static_assert(__builtin_offsetof(RegisterMap, vid_screen_size) == 0x98);
|
|
static_assert(__builtin_offsetof(RegisterMap, vid_desktop_start_addr) == 0xe4);
|
|
static_assert(__builtin_offsetof(RegisterMap, vid_desktop_overlay_stride) == 0xe8);
|
|
}
|