1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 08:34:57 +00:00
serenity/Kernel/Devices/GPU/3dfx/GraphicsAdapter.cpp
Edwin Rijkee 8388fe51b5 Kernel: Add a framebuffer driver for 3Dfx Voodoo 3
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.
2023-10-16 01:25:45 +02:00

70 lines
2.7 KiB
C++

/*
* Copyright (c) 2023, Edwin Rijkee <edwin@virtualparadise.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Bus/PCI/API.h>
#include <Kernel/Bus/PCI/IDs.h>
#include <Kernel/Devices/GPU/3dfx/Definitions.h>
#include <Kernel/Devices/GPU/3dfx/GraphicsAdapter.h>
#include <Kernel/Devices/GPU/3dfx/VoodooDisplayConnector.h>
namespace Kernel {
static constexpr u16 supported_models[] {
// 0x0003, // Banshee (untested)
0x0005, // Voodoo 3
// 0x0009 // Voodoo 4 / Voodoo 5 (untested)
};
static bool is_supported_model(u16 device_id)
{
for (auto& id : supported_models) {
if (id == device_id)
return true;
}
return false;
}
UNMAP_AFTER_INIT ErrorOr<bool> VoodooGraphicsAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier)
{
PCI::HardwareID id = pci_device_identifier.hardware_id();
return id.vendor_id == PCI::VendorID::Tdfx && is_supported_model(id.device_id);
}
UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<GenericGraphicsAdapter>> VoodooGraphicsAdapter::create(PCI::DeviceIdentifier const& pci_device_identifier)
{
auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) VoodooGraphicsAdapter(pci_device_identifier)));
MUST(adapter->initialize_adapter(pci_device_identifier));
return adapter;
}
UNMAP_AFTER_INIT VoodooGraphicsAdapter::VoodooGraphicsAdapter(PCI::DeviceIdentifier const& device_identifier)
: PCI::Device(const_cast<PCI::DeviceIdentifier&>(device_identifier))
{
}
UNMAP_AFTER_INIT ErrorOr<void> VoodooGraphicsAdapter::initialize_adapter(PCI::DeviceIdentifier const& pci_device_identifier)
{
PCI::enable_io_space(device_identifier());
PCI::enable_memory_space(device_identifier());
auto mmio_addr = PhysicalAddress(PCI::get_BAR0(pci_device_identifier) & PCI::bar_address_mask);
auto mmio_size = PCI::get_BAR_space_size(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0);
dbgln_if(TDFX_DEBUG, "3dfx mmio addr {} size {}", mmio_addr, mmio_size);
auto mmio_mapping = TRY(Memory::map_typed<VoodooGraphics::RegisterMap volatile>(mmio_addr, mmio_size, Memory::Region::Access::Read | Memory::Region::Access::Write));
auto vmem_addr = PhysicalAddress(PCI::get_BAR1(pci_device_identifier) & PCI::bar_address_mask);
auto vmem_size = PCI::get_BAR_space_size(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR1);
dbgln_if(TDFX_DEBUG, "3dfx vmem addr {} size {}", vmem_addr, vmem_size);
auto io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR2));
m_display_connector = VoodooGraphics::VoodooDisplayConnector::must_create(vmem_addr, vmem_size, move(mmio_mapping), move(io_window));
TRY(m_display_connector->set_safe_mode_setting());
return {};
}
}