intel: hotplug handler + cursor plane (Phase 1 + Phase 3)
Add hotplug.rs — HPD interrupt handling for monitor connect/disconnect. - PORT_HOTPLUG_EN/STAT at 0x61110/0x61114 per-port HPD detection - GEN11_DE_HPD_ISR/IMR/IIR/IER at 0x44470-0x4447C for Xe2 - GEN8_DE_PORT_ISR/IMR for Gen9 legacy path - init() enables HPD on all 6 ports, check_events() reads ISR - Distinguishes long pulse (connect/disconnect) from short pulse (EDID change) Add cursor.rs — hardware cursor plane. - CURCNTR/CURPOS/CURBASE via IntelRegs trait (multi-generation) - enable() with 64x64 ARGB8888 + gamma, disable(), set_position() - update() atomically sets surface + position for tear-free cursor Wire both into IntelDriver constructor and struct. Linux reference: intel_cursor.c, intel_hotplug.c
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use log::debug;
|
||||
use redox_driver_sys::memory::MmioRegion;
|
||||
|
||||
use super::regs::IntelRegs;
|
||||
use crate::driver::Result;
|
||||
|
||||
pub struct CursorPlane {
|
||||
mmio: Arc<MmioRegion>,
|
||||
regs: &'static dyn IntelRegs,
|
||||
}
|
||||
|
||||
impl CursorPlane {
|
||||
pub fn new(mmio: Arc<MmioRegion>, regs: &'static dyn IntelRegs) -> Self {
|
||||
Self { mmio, regs }
|
||||
}
|
||||
|
||||
pub fn set_position(&self, pipe: u8, x: u16, y: u16) -> Result<()> {
|
||||
let pos_reg = self.regs.curpos(pipe);
|
||||
let pos_val = ((y as u32 & 0xFFF) << 16) | (x as u32 & 0xFFF);
|
||||
self.mmio.write_u32(pos_reg, pos_val);
|
||||
debug!("redox-drm-intel: cursor pipe {} position ({}, {})", pipe, x, y);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_surface(&self, pipe: u8, gtt_offset: u32) -> Result<()> {
|
||||
let base_reg = self.regs.curbase(pipe);
|
||||
self.mmio.write_u32(base_reg, gtt_offset);
|
||||
debug!("redox-drm-intel: cursor pipe {} surface at {:#010x}", pipe, gtt_offset);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enable(&self, pipe: u8) -> Result<()> {
|
||||
let cntr = self.regs.curcntr(pipe);
|
||||
let mode_128x128: u32 = 0 << 28;
|
||||
let mode_64x64: u32 = 1 << 28;
|
||||
let mode_argb8888: u32 = 1 << 24;
|
||||
let gamma_enable: u32 = 1 << 16;
|
||||
let pipe_select: u32 = (pipe as u32) << 28;
|
||||
|
||||
let val = mode_64x64 | mode_argb8888 | gamma_enable;
|
||||
self.mmio.write_u32(cntr, val | pipe_select);
|
||||
debug!("redox-drm-intel: cursor enabled on pipe {}", pipe);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn disable(&self, pipe: u8) -> Result<()> {
|
||||
let cntr = self.regs.curcntr(pipe);
|
||||
self.mmio.write_u32(cntr, 0);
|
||||
debug!("redox-drm-intel: cursor disabled on pipe {}", pipe);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_visible(&self, pipe: u8) -> bool {
|
||||
let cntr = self.regs.curcntr(pipe);
|
||||
let val = self.mmio.read_u32(cntr);
|
||||
val & 0x80000000 != 0
|
||||
}
|
||||
|
||||
pub fn update(&self, pipe: u8, gtt_offset: u32, x: u16, y: u16) -> Result<()> {
|
||||
let base_reg = self.regs.curbase(pipe);
|
||||
self.mmio.write_u32(base_reg, gtt_offset);
|
||||
let pos_reg = self.regs.curpos(pipe);
|
||||
let pos_val = ((y as u32 & 0xFFF) << 16) | (x as u32 & 0xFFF);
|
||||
self.mmio.write_u32(pos_reg, pos_val);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use log::{debug, info};
|
||||
use redox_driver_sys::memory::MmioRegion;
|
||||
|
||||
use super::info::IntelDeviceInfo;
|
||||
use crate::driver::Result;
|
||||
|
||||
const PORT_HOTPLUG_EN: usize = 0x61110;
|
||||
const PORT_HOTPLUG_STAT: usize = 0x61114;
|
||||
const GEN11_DE_HPD_ISR: usize = 0x44470;
|
||||
const GEN11_DE_HPD_IMR: usize = 0x44474;
|
||||
const GEN11_DE_HPD_IIR: usize = 0x44478;
|
||||
const GEN11_DE_HPD_IER: usize = 0x4447C;
|
||||
|
||||
const GEN8_DE_PORT_ISR: usize = 0x44400;
|
||||
const GEN8_DE_PORT_IMR: usize = 0x44404;
|
||||
|
||||
const HPD_PORT_A: u8 = 0;
|
||||
const HPD_PORT_B: u8 = 1;
|
||||
const HPD_PORT_C: u8 = 2;
|
||||
const HPD_PORT_D: u8 = 3;
|
||||
const HPD_PORT_E: u8 = 4;
|
||||
const HPD_PORT_F: u8 = 5;
|
||||
|
||||
const MAX_PORTS: u8 = 6;
|
||||
|
||||
const HPD_LONG_DETECT: u32 = 1 << 2;
|
||||
const HPD_SHORT_DETECT: u32 = 1 << 1;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct HotplugEvent {
|
||||
pub port: u8,
|
||||
pub long_pulse: bool,
|
||||
pub short_pulse: bool,
|
||||
}
|
||||
|
||||
pub struct HotplugHandler {
|
||||
mmio: Arc<MmioRegion>,
|
||||
is_xe2: bool,
|
||||
}
|
||||
|
||||
impl HotplugHandler {
|
||||
pub fn new(mmio: Arc<MmioRegion>, device_info: &IntelDeviceInfo) -> Self {
|
||||
let is_xe2 = device_info.generation == super::info::IntelGeneration::GenXe2;
|
||||
Self { mmio, is_xe2 }
|
||||
}
|
||||
|
||||
pub fn init(&self) -> Result<()> {
|
||||
info!("redox-drm-intel: enabling hotplug detection");
|
||||
|
||||
for port in 0..MAX_PORTS {
|
||||
self.enable_port_hpd(port)?;
|
||||
}
|
||||
|
||||
if self.is_xe2 {
|
||||
self.mmio.write_u32(GEN11_DE_HPD_IER, 0x3F);
|
||||
self.mmio.write_u32(GEN11_DE_HPD_IMR, 0);
|
||||
debug!("redox-drm-intel: Xe2 HPD interrupts enabled");
|
||||
} else {
|
||||
let imr = self.mmio.read_u32(GEN8_DE_PORT_IMR);
|
||||
self.mmio.write_u32(GEN8_DE_PORT_IMR, imr & !0xFC00);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn enable_port_hpd(&self, port: u8) -> Result<()> {
|
||||
let en_reg = PORT_HOTPLUG_EN;
|
||||
let current = self.mmio.read_u32(en_reg);
|
||||
let hpd_bit = 1u32 << (port as u32 + 16);
|
||||
if current & hpd_bit == 0 {
|
||||
self.mmio.write_u32(en_reg, current | hpd_bit);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_events(&self) -> Vec<HotplugEvent> {
|
||||
let mut events = Vec::new();
|
||||
let isr = if self.is_xe2 {
|
||||
self.mmio.read_u32(GEN11_DE_HPD_ISR)
|
||||
} else {
|
||||
self.mmio.read_u32(GEN8_DE_PORT_ISR)
|
||||
};
|
||||
|
||||
for port in 0..MAX_PORTS {
|
||||
let port_bit = 1u32 << (port as u32 + 3);
|
||||
if isr & port_bit != 0 {
|
||||
let stat = self.mmio.read_u32(PORT_HOTPLUG_STAT);
|
||||
let port_stat = (stat >> (port as u32 * 4)) & 0xF;
|
||||
events.push(HotplugEvent {
|
||||
port,
|
||||
long_pulse: port_stat & HPD_LONG_DETECT != 0,
|
||||
short_pulse: port_stat & HPD_SHORT_DETECT != 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if !events.is_empty() {
|
||||
debug!("redox-drm-intel: {} hotplug event(s)", events.len());
|
||||
}
|
||||
events
|
||||
}
|
||||
|
||||
pub fn ack_events(&self, events: &[HotplugEvent]) {
|
||||
let iir = if self.is_xe2 { GEN11_DE_HPD_IIR } else { GEN8_DE_PORT_ISR + 8 };
|
||||
for event in events {
|
||||
let port_bit = 1u32 << (event.port as u32 + 3);
|
||||
self.mmio.write_u32(iir, port_bit);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_connected(&self, port: u8) -> bool {
|
||||
let stat = self.mmio.read_u32(PORT_HOTPLUG_STAT);
|
||||
let port_stat = (stat >> (port as u32 * 4)) & 0xF;
|
||||
port_stat & HPD_LONG_DETECT != 0
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod cursor;
|
||||
pub mod display;
|
||||
pub mod display_cdclk;
|
||||
pub mod display_combo_phy;
|
||||
@@ -7,6 +8,7 @@ pub mod display_power;
|
||||
pub mod dp_aux;
|
||||
pub mod gmbus;
|
||||
pub mod gtt;
|
||||
pub mod hotplug;
|
||||
pub mod info;
|
||||
pub mod regs;
|
||||
pub mod regs_gen9;
|
||||
@@ -29,6 +31,7 @@ use crate::kms::crtc::Crtc;
|
||||
use crate::kms::encoder::Encoder;
|
||||
use crate::kms::{ConnectorInfo, ConnectorType, ModeInfo};
|
||||
|
||||
use self::cursor::CursorPlane;
|
||||
use self::display::{DisplayPipe, IntelDisplay};
|
||||
use self::display_cdclk::DisplayClock;
|
||||
use self::display_combo_phy::ComboPhy;
|
||||
@@ -38,6 +41,7 @@ use self::display_power::DisplayPower;
|
||||
use self::dp_aux::DpAux;
|
||||
use self::gmbus::GmbusController;
|
||||
use self::gtt::IntelGtt;
|
||||
use self::hotplug::HotplugHandler;
|
||||
use self::info::{IntelDeviceInfo, IntelGeneration, device_info_from_id};
|
||||
use self::regs::IntelRegs;
|
||||
use self::regs_gen9::Gen9Regs;
|
||||
@@ -78,6 +82,8 @@ pub struct IntelDriver {
|
||||
dpll: DisplayPll,
|
||||
dmc: DmcFirmware,
|
||||
cdclk: DisplayClock,
|
||||
cursor: CursorPlane,
|
||||
hotplug: HotplugHandler,
|
||||
}
|
||||
|
||||
impl IntelDriver {
|
||||
@@ -200,6 +206,11 @@ impl IntelDriver {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let cursor = CursorPlane::new(mmio_arc.clone(), regs);
|
||||
|
||||
let hotplug = HotplugHandler::new(mmio_arc.clone(), &device_info);
|
||||
hotplug.init()?;
|
||||
|
||||
let (connectors, encoders) = detect_display_topology(&display, edid_source)?;
|
||||
let crtcs = build_crtcs(&display)?;
|
||||
|
||||
@@ -252,6 +263,8 @@ impl IntelDriver {
|
||||
display_power,
|
||||
dmc,
|
||||
cdclk,
|
||||
cursor,
|
||||
hotplug,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user