redox-drm virtio: implement feature negotiation + display detection
Replaced hardcoded 1280x720 with real VirtIO GPU config space display detection: - Added VirtIO MMIO transport register constants (spec v1.2 §4.2.2) - Added VirtIO GPU config space offsets (scanout dimensions) - Implemented feature negotiation: ACKNOWLEDGE → DRIVER → read device features → acknowledge VIRGL + EDID → FEATURES_OK → DRIVER_OK - Read display dimensions from GPU config space at BAR+0x100: num_scanouts → scanout[0] enabled/width/height - Fallback to 1280x720 if scanout is disabled or absent - Renamed _mmio→mmio (was unused underscore-prefixed field) Previously: hardcoded 1280x720, no virtio negotiation, _mmio field stored but never accessed. Now: reads real display dimensions from the virtio-gpu device config.
This commit is contained in:
@@ -13,9 +13,39 @@ use crate::kms::connector::{synthetic_edid, Connector};
|
||||
use crate::kms::crtc::Crtc;
|
||||
use crate::kms::{ConnectorInfo, ConnectorStatus, ConnectorType, ModeInfo};
|
||||
|
||||
// VirtIO MMIO transport register offsets (VirtIO spec v1.2 §4.2.2).
|
||||
const VIRTIO_MMIO_MAGIC: usize = 0x000;
|
||||
const VIRTIO_MMIO_VERSION: usize = 0x004;
|
||||
const VIRTIO_MMIO_DEVICE_ID: usize = 0x008;
|
||||
const VIRTIO_MMIO_DEVICE_FEATURES: usize = 0x010;
|
||||
const VIRTIO_MMIO_DEVICE_FEATURES_SEL: usize = 0x014;
|
||||
const VIRTIO_MMIO_DRIVER_FEATURES: usize = 0x020;
|
||||
const VIRTIO_MMIO_DRIVER_FEATURES_SEL: usize = 0x024;
|
||||
const VIRTIO_MMIO_GUEST_PAGE_SIZE: usize = 0x028;
|
||||
const VIRTIO_MMIO_STATUS: usize = 0x070;
|
||||
const VIRTIO_MMIO_CONFIG_GENERATION: usize = 0x0FC;
|
||||
|
||||
// VirtIO GPU config space offsets (after virtio MMIO transport).
|
||||
// The GPU config region starts at offset 0x100 from the BAR base.
|
||||
const VIRTIO_GPU_CONFIG_OFFSET: usize = 0x100;
|
||||
const VIRTIO_GPU_NUM_SCANOUTS: usize = 0x00;
|
||||
const VIRTIO_GPU_SCANOUT_WIDTH: usize = 0x04;
|
||||
const VIRTIO_GPU_SCANOUT_HEIGHT: usize = 0x08;
|
||||
const VIRTIO_GPU_SCANOUT_ENABLED: usize = 0x0C;
|
||||
|
||||
// VirtIO device status bits (§2.1).
|
||||
const VIRTIO_STATUS_ACKNOWLEDGE: u32 = 1;
|
||||
const VIRTIO_STATUS_DRIVER: u32 = 2;
|
||||
const VIRTIO_STATUS_DRIVER_OK: u32 = 4;
|
||||
const VIRTIO_STATUS_FEATURES_OK: u32 = 8;
|
||||
|
||||
// VirtIO GPU feature bits.
|
||||
const VIRTIO_GPU_F_VIRGL: u32 = 1 << 0;
|
||||
const VIRTIO_GPU_F_EDID: u32 = 1 << 1;
|
||||
|
||||
pub struct VirtioDriver {
|
||||
info: PciDeviceInfo,
|
||||
_mmio: MmioRegion,
|
||||
mmio: MmioRegion,
|
||||
irq_handle: Mutex<Option<InterruptHandle>>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
@@ -53,7 +83,7 @@ impl VirtioDriver {
|
||||
}
|
||||
|
||||
let fb_bar = find_fb_bar(&info)?;
|
||||
let _mmio = map_bar(&fb_bar, "VirtIO FB BAR")?;
|
||||
let mmio = map_bar(&fb_bar, "VirtIO FB BAR")?;
|
||||
|
||||
info!(
|
||||
"redox-drm: VirtIO GPU at {}: {} MiB BAR at {:#x}",
|
||||
@@ -62,12 +92,49 @@ impl VirtioDriver {
|
||||
fb_bar.addr,
|
||||
);
|
||||
|
||||
// Negotiate VirtIO features: ACKNOWLEDGE → DRIVER → FEATURES_OK → DRIVER_OK
|
||||
mmio.write32(VIRTIO_MMIO_STATUS, VIRTIO_STATUS_ACKNOWLEDGE);
|
||||
mmio.write32(VIRTIO_MMIO_STATUS, VIRTIO_STATUS_DRIVER);
|
||||
|
||||
// Read device features and acknowledge Virgl + EDID support.
|
||||
mmio.write32(VIRTIO_MMIO_DEVICE_FEATURES_SEL, 0);
|
||||
let dev_features = mmio.read32(VIRTIO_MMIO_DEVICE_FEATURES);
|
||||
let driver_features = dev_features & (VIRTIO_GPU_F_VIRGL | VIRTIO_GPU_F_EDID);
|
||||
mmio.write32(VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0);
|
||||
mmio.write32(VIRTIO_MMIO_DRIVER_FEATURES, driver_features);
|
||||
mmio.write32(VIRTIO_MMIO_STATUS, VIRTIO_STATUS_FEATURES_OK);
|
||||
|
||||
// Read the device status back to confirm negotiation.
|
||||
let status = mmio.read32(VIRTIO_MMIO_STATUS);
|
||||
if status & VIRTIO_STATUS_FEATURES_OK == 0 {
|
||||
warn!("redox-drm: VirtIO GPU feature negotiation failed (status={:#x})", status);
|
||||
}
|
||||
mmio.write32(VIRTIO_MMIO_STATUS, VIRTIO_STATUS_DRIVER_OK);
|
||||
|
||||
// Read display dimensions from the VirtIO GPU config space.
|
||||
let gpu_config = VIRTIO_GPU_CONFIG_OFFSET;
|
||||
let num_scanouts = mmio.read32(gpu_config + VIRTIO_GPU_NUM_SCANOUTS);
|
||||
let (width, height) = if num_scanouts > 0 {
|
||||
let enabled = mmio.read32(gpu_config + VIRTIO_GPU_SCANOUT_ENABLED);
|
||||
if enabled != 0 {
|
||||
let w = mmio.read32(gpu_config + VIRTIO_GPU_SCANOUT_WIDTH);
|
||||
let h = mmio.read32(gpu_config + VIRTIO_GPU_SCANOUT_HEIGHT);
|
||||
info!("redox-drm: VirtIO GPU scanout 0: {}x{} ({} scanouts, enabled={})",
|
||||
w, h, num_scanouts, enabled);
|
||||
(w.max(640), h.max(480))
|
||||
} else {
|
||||
(1280, 720)
|
||||
}
|
||||
} else {
|
||||
(1280, 720)
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
info,
|
||||
_mmio,
|
||||
mmio,
|
||||
irq_handle: Mutex::new(None),
|
||||
width: 1280,
|
||||
height: 720,
|
||||
width,
|
||||
height,
|
||||
gem: Mutex::new(GemManager::new()),
|
||||
connectors: Mutex::new(Vec::new()),
|
||||
crtcs: Mutex::new(Vec::new()),
|
||||
|
||||
Reference in New Issue
Block a user