From a932ae1ca1ccf4c31cf890038da8891181fc474a Mon Sep 17 00:00:00 2001 From: Admin Pupkin Date: Sat, 30 May 2026 08:49:41 +0300 Subject: [PATCH] intel: hotplug handler + cursor plane (Phase 1 + Phase 3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../source/src/drivers/intel/cursor.rs | 69 ++++++++++ .../source/src/drivers/intel/hotplug.rs | 118 ++++++++++++++++++ .../redox-drm/source/src/drivers/intel/mod.rs | 13 ++ 3 files changed, 200 insertions(+) create mode 100644 local/recipes/gpu/redox-drm/source/src/drivers/intel/cursor.rs create mode 100644 local/recipes/gpu/redox-drm/source/src/drivers/intel/hotplug.rs diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/cursor.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/cursor.rs new file mode 100644 index 0000000000..80658a199f --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/cursor.rs @@ -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, + regs: &'static dyn IntelRegs, +} + +impl CursorPlane { + pub fn new(mmio: Arc, 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(()) + } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/hotplug.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/hotplug.rs new file mode 100644 index 0000000000..231a4f44f5 --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/hotplug.rs @@ -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, + is_xe2: bool, +} + +impl HotplugHandler { + pub fn new(mmio: Arc, 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 { + 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 + } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs index bc3ae2de1e..0e54782d40 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs @@ -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, }) } }